other-licenses/nsis/Contrib/InetBgDL/InetBgDL.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 //
     2 // Copyright (C) Anders Kjersem. Licensed under the zlib/libpng license
     3 //
     5 #include "InetBgDL.h"
     7 #define USERAGENT _T("NSIS InetBgDL (Mozilla)")
     9 #define STATUS_COMPLETEDALL 0
    10 #define STATUS_INITIAL 202
    11 #define STATUS_CONNECTING STATUS_INITIAL //102
    12 #define STATUS_DOWNLOADING STATUS_INITIAL
    13 #define STATUS_ERR_GETLASTERROR 418 //HTTP: I'm a teapot: Win32 error code in $3
    14 #define STATUS_ERR_LOCALFILEWRITEERROR 450 //HTTP: MS parental control extension
    15 #define STATUS_ERR_CANCELLED 499
    17 typedef DWORD FILESIZE_T; // Limit to 4GB for now...
    18 #define FILESIZE_UNKNOWN (-1)
    20 #define MAX_STRLEN 1024
    22 HINSTANCE g_hInst;
    23 NSIS::stack_t*g_pLocations = NULL;
    24 HANDLE g_hThread = NULL;
    25 HANDLE g_hGETStartedEvent = NULL;
    26 volatile UINT g_FilesTotal = 0;
    27 volatile UINT g_FilesCompleted = 0;
    28 volatile UINT g_Status = STATUS_INITIAL;
    29 volatile FILESIZE_T g_cbCurrXF;
    30 volatile FILESIZE_T g_cbCurrTot = FILESIZE_UNKNOWN;
    31 CRITICAL_SECTION g_CritLock;
    32 UINT g_N_CCH;
    33 PTSTR g_N_Vars;
    34 TCHAR g_ServerIP[128] = { _T('\0') };
    36 DWORD g_ConnectTimeout = 0;
    37 DWORD g_ReceiveTimeout = 0;
    39 #define NSISPI_INITGLOBALS(N_CCH, N_Vars) do { \
    40   g_N_CCH = N_CCH; \
    41   g_N_Vars = N_Vars; \
    42   } while(0)
    44 #define ONELOCKTORULETHEMALL
    45 #ifdef ONELOCKTORULETHEMALL
    46 #define TaskLock_AcquireExclusive() EnterCriticalSection(&g_CritLock)
    47 #define TaskLock_ReleaseExclusive() LeaveCriticalSection(&g_CritLock)
    48 #define StatsLock_AcquireExclusive() TaskLock_AcquireExclusive()
    49 #define StatsLock_ReleaseExclusive() TaskLock_ReleaseExclusive()
    50 #define StatsLock_AcquireShared() StatsLock_AcquireExclusive()
    51 #define StatsLock_ReleaseShared() StatsLock_ReleaseExclusive()
    52 #endif
    54 PTSTR NSIS_SetRegStr(UINT Reg, LPCTSTR Value)
    55 {
    56   PTSTR s = g_N_Vars + (Reg * g_N_CCH);
    57   lstrcpy(s, Value);
    58   return s;
    59 }
    60 #define NSIS_SetRegStrEmpty(r) NSIS_SetRegStr(r, _T(""))
    61 void NSIS_SetRegUINT(UINT Reg, UINT Value)
    62 {
    63   TCHAR buf[32];
    64   wsprintf(buf, _T("%u"), Value);
    65   NSIS_SetRegStr(Reg, buf);
    66 }
    67 #define StackFreeItem(pI) GlobalFree(pI)
    68 NSIS::stack_t* StackPopItem(NSIS::stack_t**ppST)
    69 {
    70   if (*ppST)
    71   {
    72     NSIS::stack_t*pItem = *ppST;
    73     *ppST = pItem->next;
    74     return pItem;
    75   }
    76   return NULL;
    77 }
    79 void Reset()
    80 {
    81   // The g_hGETStartedEvent event is used to make sure that the Get() call will
    82   // acquire the lock before the Reset() call acquires the lock.
    83   if (g_hGETStartedEvent) {
    84     TRACE(_T("InetBgDl: waiting on g_hGETStartedEvent\n"));
    85     WaitForSingleObject(g_hGETStartedEvent, INFINITE);
    86     CloseHandle(g_hGETStartedEvent);
    87     g_hGETStartedEvent = NULL;
    88   }
    90   TaskLock_AcquireExclusive();
    91 #ifndef ONELOCKTORULETHEMALL
    92   StatsLock_AcquireExclusive();
    93 #endif
    94   g_FilesTotal = 0; // This causes the Task thread to exit the transfer loop
    95   if (g_hThread)
    96   {
    97     TRACE(_T("InetBgDl: waiting on g_hThread\n"));
    98     if (WAIT_OBJECT_0 != WaitForSingleObject(g_hThread, 10 * 1000))
    99     {
   100       TRACE(_T("InetBgDl: terminating g_hThread\n"));
   101       TerminateThread(g_hThread, ERROR_OPERATION_ABORTED);
   102     }
   103     CloseHandle(g_hThread);
   104     g_hThread = NULL;
   105   }
   106   g_FilesTotal = 0;
   107   g_FilesCompleted = 0;
   108   g_Status = STATUS_INITIAL;
   109 #ifndef ONELOCKTORULETHEMALL
   110   StatsLock_ReleaseExclusive();
   111 #endif
   112   for (NSIS::stack_t*pTmpTast,*pTask = g_pLocations; pTask ;)
   113   {
   114     pTmpTast = pTask;
   115     pTask = pTask->next;
   116     StackFreeItem(pTmpTast);
   117   }
   118   g_pLocations = NULL;
   119   TaskLock_ReleaseExclusive();
   120 }
   122 UINT_PTR __cdecl NSISPluginCallback(UINT Event)
   123 {
   124   switch(Event)
   125   {
   126   case NSPIM_UNLOAD:
   127     Reset();
   128     break;
   129   }
   130   return NULL;
   131 }
   133 void __stdcall InetStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext,
   134                                   DWORD dwInternetStatus,
   135                                   LPVOID lpvStatusInformation,
   136                                   DWORD dwStatusInformationLength)
   137 {
   138   if (dwInternetStatus == INTERNET_STATUS_NAME_RESOLVED) {
   139     // The documentation states the IP address is a PCTSTR but it is usually a
   140     // PCSTR and only sometimes a PCTSTR.
   141     StatsLock_AcquireExclusive();
   142     wsprintf(g_ServerIP, _T("%S"), lpvStatusInformation);
   143     if (wcslen(g_ServerIP) == 1)
   144     {
   145       wsprintf(g_ServerIP, _T("%s"), lpvStatusInformation);
   146     }
   147     StatsLock_ReleaseExclusive();
   148   }
   150 #if defined(PLUGIN_DEBUG)
   151   switch (dwInternetStatus)
   152   {
   153     case INTERNET_STATUS_RESOLVING_NAME:
   154       TRACE(_T("InetBgDl: INTERNET_STATUS_RESOLVING_NAME (%d), name=%s\n"),
   155             dwStatusInformationLength, lpvStatusInformation);
   156       break;
   157     case INTERNET_STATUS_NAME_RESOLVED:
   158       TRACE(_T("InetBgDl: INTERNET_STATUS_NAME_RESOLVED (%d), resolved name=%s\n"),
   159             dwStatusInformationLength, g_ServerIP);
   160       break;
   161     case INTERNET_STATUS_CONNECTING_TO_SERVER:
   162       TRACE(_T("InetBgDl: INTERNET_STATUS_CONNECTING_TO_SERVER (%d)\n"),
   163             dwStatusInformationLength);
   164       break;
   165     case INTERNET_STATUS_CONNECTED_TO_SERVER:
   166       TRACE(_T("InetBgDl: INTERNET_STATUS_CONNECTED_TO_SERVER (%d)\n"),
   167             dwStatusInformationLength);
   168       break;
   169     case INTERNET_STATUS_SENDING_REQUEST:
   170       TRACE(_T("InetBgDl: INTERNET_STATUS_SENDING_REQUEST (%d)\n"),
   171                dwStatusInformationLength);
   172       break;
   173     case INTERNET_STATUS_REQUEST_SENT:
   174       TRACE(_T("InetBgDl: INTERNET_STATUS_REQUEST_SENT (%d), bytes sent=%d\n"),
   175              dwStatusInformationLength, lpvStatusInformation);
   176       break;
   177     case INTERNET_STATUS_RECEIVING_RESPONSE:
   178       TRACE(_T("InetBgDl: INTERNET_STATUS_RECEIVING_RESPONSE (%d)\n"),
   179             dwStatusInformationLength);
   180       break;
   181     case INTERNET_STATUS_RESPONSE_RECEIVED:
   182       TRACE(_T("InetBgDl: INTERNET_STATUS_RESPONSE_RECEIVED (%d)\n"),
   183             dwStatusInformationLength);
   184       break;
   185     case INTERNET_STATUS_CTL_RESPONSE_RECEIVED:
   186       TRACE(_T("InetBgDl: INTERNET_STATUS_CTL_RESPONSE_RECEIVED (%d)\n"),
   187             dwStatusInformationLength);
   188       break;
   189     case INTERNET_STATUS_PREFETCH:
   190       TRACE(_T("InetBgDl: INTERNET_STATUS_PREFETCH (%d)\n"),
   191             dwStatusInformationLength);
   192       break;
   193     case INTERNET_STATUS_CLOSING_CONNECTION:
   194       TRACE(_T("InetBgDl: INTERNET_STATUS_CLOSING_CONNECTION (%d)\n"),
   195             dwStatusInformationLength);
   196       break;
   197     case INTERNET_STATUS_CONNECTION_CLOSED:
   198       TRACE(_T("InetBgDl: INTERNET_STATUS_CONNECTION_CLOSED (%d)\n"),
   199             dwStatusInformationLength);
   200       break;
   201     case INTERNET_STATUS_HANDLE_CREATED:
   202       TRACE(_T("InetBgDl: INTERNET_STATUS_HANDLE_CREATED (%d)\n"),
   203             dwStatusInformationLength);
   204       break;
   205     case INTERNET_STATUS_HANDLE_CLOSING:
   206       TRACE(_T("InetBgDl: INTERNET_STATUS_HANDLE_CLOSING (%d)\n"),
   207             dwStatusInformationLength);
   208       break;
   209     case INTERNET_STATUS_DETECTING_PROXY:
   210       TRACE(_T("InetBgDl: INTERNET_STATUS_DETECTING_PROXY (%d)\n"),
   211             dwStatusInformationLength);
   212       break;
   213     case INTERNET_STATUS_REQUEST_COMPLETE:
   214       TRACE(_T("InetBgDl: INTERNET_STATUS_REQUEST_COMPLETE (%d)\n"),
   215             dwStatusInformationLength);
   216       break;
   217     case INTERNET_STATUS_REDIRECT:
   218       TRACE(_T("InetBgDl: INTERNET_STATUS_REDIRECT (%d), new url=%s\n"),
   219             dwStatusInformationLength, lpvStatusInformation);
   220       break;
   221     case INTERNET_STATUS_INTERMEDIATE_RESPONSE:
   222       TRACE(_T("InetBgDl: INTERNET_STATUS_INTERMEDIATE_RESPONSE (%d)\n"),
   223             dwStatusInformationLength);
   224       break;
   225     case INTERNET_STATUS_USER_INPUT_REQUIRED:
   226       TRACE(_T("InetBgDl: INTERNET_STATUS_USER_INPUT_REQUIRED (%d)\n"),
   227             dwStatusInformationLength);
   228       break;
   229     case INTERNET_STATUS_STATE_CHANGE:
   230       TRACE(_T("InetBgDl: INTERNET_STATUS_STATE_CHANGE (%d)\n"),
   231             dwStatusInformationLength);
   232       break;
   233     case INTERNET_STATUS_COOKIE_SENT:
   234       TRACE(_T("InetBgDl: INTERNET_STATUS_COOKIE_SENT (%d)\n"),
   235             dwStatusInformationLength);
   236       break;
   237     case INTERNET_STATUS_COOKIE_RECEIVED:
   238       TRACE(_T("InetBgDl: INTERNET_STATUS_COOKIE_RECEIVED (%d)\n"),
   239             dwStatusInformationLength);
   240       break;
   241     case INTERNET_STATUS_PRIVACY_IMPACTED:
   242       TRACE(_T("InetBgDl: INTERNET_STATUS_PRIVACY_IMPACTED (%d)\n"),
   243             dwStatusInformationLength);
   244       break;
   245     case INTERNET_STATUS_P3P_HEADER:
   246       TRACE(_T("InetBgDl: INTERNET_STATUS_P3P_HEADER (%d)\n"),
   247             dwStatusInformationLength);
   248       break;
   249     case INTERNET_STATUS_P3P_POLICYREF:
   250       TRACE(_T("InetBgDl: INTERNET_STATUS_P3P_POLICYREF (%d)\n"),
   251             dwStatusInformationLength);
   252       break;
   253     case INTERNET_STATUS_COOKIE_HISTORY:
   254       TRACE(_T("InetBgDl: INTERNET_STATUS_COOKIE_HISTORY (%d)\n"),
   255             dwStatusInformationLength);
   256       break;
   257     default:
   258       TRACE(_T("InetBgDl: Unknown Status %d\n"), dwInternetStatus);
   259       break;
   260   }
   261 #endif
   262 }
   264 DWORD CALLBACK TaskThreadProc(LPVOID ThreadParam)
   265 {
   266   NSIS::stack_t *pURL,*pFile;
   267   HINTERNET hInetSes = NULL, hInetFile = NULL;
   268   DWORD cbio = sizeof(DWORD);
   269   HANDLE hLocalFile;
   270   bool completedFile = false;
   271 startnexttask:
   272   hLocalFile = INVALID_HANDLE_VALUE;
   273   pFile = NULL;
   274   TaskLock_AcquireExclusive();
   275   // Now that we've acquired the lock, we can set the event to indicate this.
   276   // SetEvent will likely never fail, but if it does we should set it to NULL
   277   // to avoid anyone waiting on it.
   278   if (!SetEvent(g_hGETStartedEvent)) {
   279     CloseHandle(g_hGETStartedEvent);
   280     g_hGETStartedEvent = NULL;
   281   }
   282   pURL = g_pLocations;
   283   if (pURL)
   284   {
   285     pFile = pURL->next;
   286     g_pLocations = pFile->next;
   287   }
   288 #ifndef ONELOCKTORULETHEMALL
   289   StatsLock_AcquireExclusive();
   290 #endif
   291   if (completedFile)
   292   {
   293     ++g_FilesCompleted;
   294   }
   295   completedFile = false;
   296   g_cbCurrXF = 0;
   297   g_cbCurrTot = FILESIZE_UNKNOWN;
   298   if (!pURL)
   299   {
   300     if (g_FilesTotal)
   301     {
   302       if (g_FilesTotal == g_FilesCompleted)
   303       {
   304         g_Status = STATUS_COMPLETEDALL;
   305       }
   306     }
   307     g_hThread = NULL;
   308   }
   309 #ifndef ONELOCKTORULETHEMALL
   310   StatsLock_ReleaseExclusive();
   311 #endif
   312   TaskLock_ReleaseExclusive();
   314   if (!pURL)
   315   {
   316     if (0)
   317     {
   318 diegle:
   319       DWORD gle = GetLastError();
   320       //TODO? if (ERROR_INTERNET_EXTENDED_ERROR==gle) InternetGetLastResponseInfo(...)
   321       g_Status = STATUS_ERR_GETLASTERROR;
   322     }
   323     if (hInetSes)
   324     {
   325       InternetCloseHandle(hInetSes);
   326     }
   327     if (INVALID_HANDLE_VALUE != hLocalFile)
   328     {
   329       CloseHandle(hLocalFile);
   330     }
   331     StackFreeItem(pURL);
   332     StackFreeItem(pFile);
   333     return 0;
   334   }
   336   if (!hInetSes)
   337   {
   338     hInetSes = InternetOpen(USERAGENT, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
   339     if (!hInetSes)
   340     {
   341       TRACE(_T("InetBgDl: InternetOpen failed with gle=%u\n"),
   342             GetLastError());
   343       goto diegle;
   344     }
   345     InternetSetStatusCallback(hInetSes, (INTERNET_STATUS_CALLBACK)InetStatusCallback);
   347     //msdn.microsoft.com/library/default.asp?url=/workshop/components/offline/offline.asp#Supporting Offline Browsing in Applications and Components
   348     ULONG longOpt;
   349     DWORD cbio = sizeof(ULONG);
   350     if (InternetQueryOption(hInetSes, INTERNET_OPTION_CONNECTED_STATE, &longOpt, &cbio))
   351     {
   352       if (INTERNET_STATE_DISCONNECTED_BY_USER&longOpt)
   353       {
   354         INTERNET_CONNECTED_INFO ci = {INTERNET_STATE_CONNECTED, 0};
   355         InternetSetOption(hInetSes, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci));
   356       }
   357     }
   359     // Change the default connect timeout if specified.
   360     if(g_ConnectTimeout > 0)
   361     {
   362       InternetSetOption(hInetSes, INTERNET_OPTION_CONNECT_TIMEOUT,
   363                         &g_ConnectTimeout, sizeof(g_ConnectTimeout));
   364     }
   366     // Change the default receive timeout if specified.
   367     if (g_ReceiveTimeout)
   368     {
   369       InternetSetOption(hInetSes, INTERNET_OPTION_RECEIVE_TIMEOUT,
   370                         &g_ReceiveTimeout, sizeof(DWORD));
   371     }
   372   }
   374   DWORD ec = ERROR_SUCCESS;
   375   hLocalFile = CreateFile(pFile->text, GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_DELETE,NULL,CREATE_ALWAYS, 0, NULL);
   376   if (INVALID_HANDLE_VALUE == hLocalFile)
   377   {
   378     TRACE(_T("InetBgDl: CreateFile file handle invalid\n"));
   379     goto diegle;
   380   }
   382   const DWORD IOURedirFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |
   383                               INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS;
   384   const DWORD IOUCacheFlags = INTERNET_FLAG_RESYNCHRONIZE |
   385                               INTERNET_FLAG_NO_CACHE_WRITE |
   386                               INTERNET_FLAG_PRAGMA_NOCACHE |
   387                               INTERNET_FLAG_RELOAD;
   388   const DWORD IOUCookieFlags = INTERNET_FLAG_NO_COOKIES;
   389   DWORD IOUFlags = IOURedirFlags | IOUCacheFlags | IOUCookieFlags |
   390                    INTERNET_FLAG_NO_UI | INTERNET_FLAG_EXISTING_CONNECT;
   392   TCHAR *hostname = (TCHAR*) GlobalAlloc(GPTR, MAX_STRLEN * sizeof(TCHAR)),
   393         *urlpath = (TCHAR*) GlobalAlloc(GPTR, MAX_STRLEN * sizeof(TCHAR)),
   394         *extrainfo = (TCHAR*) GlobalAlloc(GPTR, MAX_STRLEN * sizeof(TCHAR));
   396   URL_COMPONENTS uc = { sizeof(URL_COMPONENTS), NULL, 0, (INTERNET_SCHEME)0,
   397                         hostname, MAX_STRLEN, (INTERNET_PORT)0, NULL, 0,
   398                         NULL, 0, urlpath, MAX_STRLEN, extrainfo, MAX_STRLEN};
   399   uc.dwHostNameLength = uc.dwUrlPathLength = uc.dwExtraInfoLength = MAX_STRLEN;
   401   if (!InternetCrackUrl(pURL->text, 0, ICU_ESCAPE, &uc))
   402   {
   403     // Bad url or param passed in
   404     TRACE(_T("InetBgDl: InternetCrackUrl false with url=%s, gle=%u\n"),
   405           pURL->text, GetLastError());
   406     goto diegle;
   407   }
   409   TRACE(_T("InetBgDl: scheme_id=%d, hostname=%s, port=%d, urlpath=%s, extrainfo=%s\n"),
   410         uc.nScheme, hostname, uc.nPort, urlpath, extrainfo);
   412   // Only http and https are supported
   413   if (uc.nScheme != INTERNET_SCHEME_HTTP &&
   414       uc.nScheme != INTERNET_SCHEME_HTTPS)
   415   {
   416     TRACE(_T("InetBgDl: only http and https is supported, aborting...\n"));
   417     goto diegle;
   418   }
   420   TRACE(_T("InetBgDl: calling InternetOpenUrl with url=%s\n"), pURL->text);
   421   hInetFile = InternetOpenUrl(hInetSes, pURL->text,
   422                               NULL, 0, IOUFlags |
   423                               (uc.nScheme == INTERNET_SCHEME_HTTPS ?
   424                                INTERNET_FLAG_SECURE : 0), 1);
   425   if (!hInetFile)
   426   {
   427     TRACE(_T("InetBgDl: InternetOpenUrl failed with gle=%u\n"),
   428           GetLastError());
   429     goto diegle;
   430   }
   432   // Get the file length via the Content-Length header
   433   FILESIZE_T cbThisFile;
   434   cbio = sizeof(cbThisFile);
   435   if (!HttpQueryInfo(hInetFile,
   436                      HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
   437                      &cbThisFile, &cbio, NULL))
   438   {
   439     cbThisFile = FILESIZE_UNKNOWN;
   440   }
   441   TRACE(_T("InetBgDl: file size=%d bytes\n"), cbThisFile);
   443   // Setup a buffer of size 256KiB to store the downloaded data.
   444   const UINT cbBufXF = 262144;
   445   // Use a 4MiB read buffer for the connection.
   446   // Bigger buffers will be faster.
   447   // cbReadBufXF should be a multiple of cbBufXF.
   448   const UINT cbReadBufXF = 4194304;
   449   BYTE bufXF[cbBufXF];
   451   // Up the default internal buffer size from 4096 to internalReadBufferSize.
   452   DWORD internalReadBufferSize = cbReadBufXF;
   453   if (!InternetSetOption(hInetFile, INTERNET_OPTION_READ_BUFFER_SIZE,
   454                          &internalReadBufferSize, sizeof(DWORD)))
   455   {
   456     TRACE(_T("InetBgDl: InternetSetOption failed to set read buffer size to %u bytes, gle=%u\n"),
   457           internalReadBufferSize, GetLastError());
   459     // Maybe it's too big, try half of the optimal value.  If that fails just
   460     // use the default.
   461     internalReadBufferSize /= 2;
   462     if (!InternetSetOption(hInetFile, INTERNET_OPTION_READ_BUFFER_SIZE,
   463                            &internalReadBufferSize, sizeof(DWORD)))
   464     {
   465       TRACE(_T("InetBgDl: InternetSetOption failed to set read buffer size ") \
   466             _T("to %u bytes (using default read buffer size), gle=%u\n"),
   467             internalReadBufferSize, GetLastError());
   468     }
   469   }
   471   for(;;)
   472   {
   473     DWORD cbio = 0, cbXF = 0;
   474     BOOL retXF = InternetReadFile(hInetFile, bufXF, cbBufXF, &cbio);
   475     if (!retXF)
   476     {
   477       ec = GetLastError();
   478       TRACE(_T("InetBgDl: InternetReadFile failed, gle=%u\n"), ec);
   479       break;
   480     }
   482     if (0 == cbio)
   483     {
   484       ASSERT(ERROR_SUCCESS == ec);
   485       // EOF or broken connection?
   486       // TODO: Can InternetQueryDataAvailable detect this?
   488       TRACE(_T("InetBgDl: InternetReadFile true with 0 cbio, cbThisFile=%d, gle=%u\n"),
   489             cbThisFile, GetLastError());
   490       // If we haven't transferred all of the file, and we know how big the file
   491       // is, and we have no more data to read from the HTTP request, then set a
   492       // broken pipe error. Reading without StatsLock is ok in this thread.
   493       if (FILESIZE_UNKNOWN != cbThisFile && g_cbCurrXF != cbThisFile)
   494       {
   495         TRACE(_T("InetBgDl: downloaded file size of %d bytes doesn't equal ") \
   496               _T("expected file size of %d bytes\n"), g_cbCurrXF, cbThisFile);
   497         ec = ERROR_BROKEN_PIPE;
   498       }
   499       break;
   500     }
   502     // Check if we canceled the download
   503     if (0 == g_FilesTotal)
   504     {
   505       TRACE(_T("InetBgDl: 0 == g_FilesTotal, aborting transfer loop...\n"));
   506       ec = ERROR_CANCELLED;
   507       break;
   508     }
   510     cbXF = cbio;
   511     if (cbXF)
   512     {
   513       retXF = WriteFile(hLocalFile, bufXF, cbXF, &cbio, NULL);
   514       if (!retXF || cbXF != cbio)
   515       {
   516         ec = GetLastError();
   517         break;
   518       }
   520       StatsLock_AcquireExclusive();
   521       if (FILESIZE_UNKNOWN != cbThisFile) {
   522         g_cbCurrTot = cbThisFile;
   523       }
   524       g_cbCurrXF += cbXF;
   525       StatsLock_ReleaseExclusive();
   526     }
   527   }
   529   TRACE(_T("InetBgDl: TaskThreadProc completed %s, ec=%u\n"), pURL->text, ec);
   530   InternetCloseHandle(hInetFile);
   531   if (ERROR_SUCCESS == ec)
   532   {
   533     if (INVALID_HANDLE_VALUE != hLocalFile)
   534     {
   535       CloseHandle(hLocalFile);
   536       hLocalFile = INVALID_HANDLE_VALUE;
   537     }
   538     StackFreeItem(pURL);
   539     StackFreeItem(pFile);
   540     ++completedFile;
   541   }
   542   else
   543   {
   544     TRACE(_T("InetBgDl: failed with ec=%u\n"), ec);
   545     SetLastError(ec);
   546     goto diegle;
   547   }
   548   goto startnexttask;
   549 }
   551 NSISPIEXPORTFUNC Get(HWND hwndNSIS, UINT N_CCH, TCHAR*N_Vars, NSIS::stack_t**ppST, NSIS::xparams_t*pX)
   552 {
   553   pX->RegisterPluginCallback(g_hInst, NSISPluginCallback);
   554   for (;;)
   555   {
   556     NSIS::stack_t*pURL = StackPopItem(ppST);
   557     if (!pURL)
   558     {
   559       break;
   560     }
   562     if (lstrcmpi(pURL->text, _T("/connecttimeout")) == 0)
   563     {
   564       NSIS::stack_t*pConnectTimeout = StackPopItem(ppST);
   565       g_ConnectTimeout = _tcstol(pConnectTimeout->text, NULL, 10) * 1000;
   566       continue;
   567     }
   568     else if (lstrcmpi(pURL->text, _T("/receivetimeout")) == 0)
   569     {
   570       NSIS::stack_t*pReceiveTimeout = StackPopItem(ppST);
   571       g_ReceiveTimeout = _tcstol(pReceiveTimeout->text, NULL, 10) * 1000;
   572       continue;
   573     }
   574     else if (lstrcmpi(pURL->text, _T("/reset")) == 0)
   575     {
   576       StackFreeItem(pURL);
   577       Reset();
   578       continue;
   579     }
   580     else if (lstrcmpi(pURL->text, _T("/end")) == 0)
   581     {
   582 freeurlandexit:
   583       StackFreeItem(pURL);
   584       break;
   585     }
   587     NSIS::stack_t*pFile = StackPopItem(ppST);
   588     if (!pFile)
   589     {
   590       goto freeurlandexit;
   591     }
   593     TaskLock_AcquireExclusive();
   595     pFile->next = NULL;
   596     pURL->next = pFile;
   597     NSIS::stack_t*pTasksTail = g_pLocations;
   598     while(pTasksTail && pTasksTail->next) pTasksTail = pTasksTail->next;
   599     if (pTasksTail)
   600     {
   601       pTasksTail->next = pURL;
   602     }
   603     else
   604     {
   605       g_pLocations = pURL;
   606     }
   608     if (!g_hThread)
   609     {
   610       DWORD tid;
   611       if (g_hGETStartedEvent) {
   612         CloseHandle(g_hGETStartedEvent);
   613       }
   614       g_hGETStartedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
   615       g_hThread = CreateThread(NULL, 0, TaskThreadProc, NULL, 0, &tid);
   616     }
   618     if (!g_hThread)
   619     {
   620       goto freeurlandexit;
   621     }
   623 #ifndef ONELOCKTORULETHEMALL
   624     StatsLock_AcquireExclusive();
   625 #endif
   626     ++g_FilesTotal;
   627 #ifndef ONELOCKTORULETHEMALL
   628     StatsLock_ReleaseExclusive();
   629 #endif
   630     TaskLock_ReleaseExclusive();
   631   }
   632 }
   634 NSISPIEXPORTFUNC GetStats(HWND hwndNSIS, UINT N_CCH, TCHAR*N_Vars, NSIS::stack_t**ppST, NSIS::xparams_t*pX)
   635 {
   636   NSISPI_INITGLOBALS(N_CCH, N_Vars);
   637   StatsLock_AcquireShared();
   638   NSIS_SetRegUINT(0, g_Status);
   639   NSIS_SetRegUINT(1, g_FilesCompleted);
   640   NSIS_SetRegUINT(2, g_FilesTotal - g_FilesCompleted);
   641   NSIS_SetRegUINT(3, g_cbCurrXF);
   642   NSIS_SetRegStrEmpty(4);
   643   if (FILESIZE_UNKNOWN != g_cbCurrTot)
   644   {
   645     NSIS_SetRegUINT(4, g_cbCurrTot);
   646   }
   647   NSIS_SetRegStr(5, g_ServerIP);
   648   StatsLock_ReleaseShared();
   649 }
   651 EXTERN_C BOOL WINAPI _DllMainCRTStartup(HMODULE hInst, UINT Reason, LPVOID pCtx)
   652 {
   653   if (DLL_PROCESS_ATTACH==Reason)
   654   {
   655     g_hInst=hInst;
   656     InitializeCriticalSection(&g_CritLock);
   657   }
   658   return TRUE;
   659 }
   661 BOOL WINAPI DllMain(HINSTANCE hInst, ULONG Reason, LPVOID pCtx)
   662 {
   663   return _DllMainCRTStartup(hInst, Reason, pCtx);
   664 }
   666 // For some reason VC6++ doesn't like wcsicmp and swprintf.
   667 // If you use them, you get a linking error about _main
   668 // as an unresolved external.
   669 int main(int argc, char**argv)
   670 {
   671   return 0;
   672 }

mercurial