Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/other-licenses/nsis/Contrib/InetBgDL/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 22 kB image not shown  

Quelle  InetBgDL.cpp   Sprache: C

 
//
// Copyright (C) Anders Kjersem. Licensed under the zlib/libpng license
//

// This file is intended to be compiled with MSVC's Omit Default Library Name (/Zl)
// option enabled, in order to keep the file size low for bundling this DLL with
// the stub installer. That means that any code requiring the C runtime will fail
// to link. You'll see a couple of odd-looking things here for this reason; they
// should all be called out with comments.

#include "InetBgDL.h"

#define USERAGENT _T("NSIS InetBgDL (Mozilla 2024)")

#define STATUS_COMPLETEDALL 0
#define STATUS_INITIAL 202
#define STATUS_CONNECTING STATUS_INITIAL //102
#define STATUS_DOWNLOADING STATUS_INITIAL
#define STATUS_ERR_GETLASTERROR 418 //HTTP: I'm a teapot: Win32 error code in $3
#define STATUS_ERR_LOCALFILEWRITEERROR 450 //HTTP: MS parental control extension
#define STATUS_ERR_CANCELLED 499
#define STATUS_ERR_CONNECTION_LOST 1000

typedef DWORD FILESIZE_T; // Limit to 4GB for now...
#define FILESIZE_UNKNOWN (-1)

#define MAX_STRLEN 1024

HINSTANCE g_hInst;
NSIS::stack_t*g_pLocations = NULL;
HANDLE g_hThread = NULL;
HANDLE g_hGETStartedEvent = NULL;
HINTERNET g_hInetSes = NULL;
HINTERNET g_hInetFile = NULL;
volatile UINT g_FilesTotal = 0;
volatile UINT g_FilesCompleted = 0;
volatile UINT g_Status = STATUS_INITIAL;
volatile FILESIZE_T g_cbCurrXF;
volatile FILESIZE_T g_cbCurrTot = FILESIZE_UNKNOWN;
CRITICAL_SECTION g_CritLock;
UINT g_N_CCH;
PTSTR g_N_Vars;
TCHAR g_ServerIP[128] = { _T('\0') };

DWORD g_ConnectTimeout = 0;
DWORD g_ReceiveTimeout = 0;

// Setup a buffer of size 256KiB to store the downloaded data.
constexpr UINT g_cbBufXF = 262144;
// This buffer is only needed inside TaskThreadProc(), but declaring it on
// the stack there triggers a runtime stack size check, which is implemented
// by a C runtime library function, so we have to avoid the compiler wanting
// to build that check by not having any large stack buffers.
BYTE g_bufXF[g_cbBufXF];

#define NSISPI_INITGLOBALS(N_CCH, N_Vars) do { \
  g_N_CCH = N_CCH; \
  g_N_Vars = N_Vars; \
  } while(0)

#define ONELOCKTORULETHEMALL
#ifdef ONELOCKTORULETHEMALL
#define TaskLock_AcquireExclusive() EnterCriticalSection(&g_CritLock)
#define TaskLock_ReleaseExclusive() LeaveCriticalSection(&g_CritLock)
#define StatsLock_AcquireExclusive() TaskLock_AcquireExclusive()
#define StatsLock_ReleaseExclusive() TaskLock_ReleaseExclusive()
#define StatsLock_AcquireShared() StatsLock_AcquireExclusive()
#define StatsLock_ReleaseShared() StatsLock_ReleaseExclusive()
#endif

// Normally we would just call the C library wcstol, but since we can't use the
// C runtime, we'll supply our own function as an understudy.
static DWORD
MyTStrToL(TCHAR const* str)
{
  if (!str) {
    return 0;
  }

  int len = lstrlen(str);
  DWORD place = 1;
  DWORD rv = 0;
  for (int i = len - 1; i >= 0; --i) {
    int digit = str[i] - 0x30;
    rv += digit * place;
    place *= 10;
  }
  return rv;
}

PTSTR NSIS_SetRegStr(UINT Reg, LPCTSTR Value)
{
  PTSTR s = g_N_Vars + (Reg * g_N_CCH);
  lstrcpy(s, Value);
  return s;
}
#define NSIS_SetRegStrEmpty(r) NSIS_SetRegStr(r, _T(""))
void NSIS_SetRegUINT(UINT Reg, UINT Value)
{
  TCHAR buf[32];
  wsprintf(buf, _T("%u"), Value);
  NSIS_SetRegStr(Reg, buf);
}
#define StackFreeItem(pI) GlobalFree(pI)
NSIS::stack_t* StackPopItem(NSIS::stack_t**ppST)
{
  if (*ppST)
  {
    NSIS::stack_t*pItem = *ppST;
    *ppST = pItem->next;
    return pItem;
  }
  return NULL;
}

void Reset()
{
  // The g_hGETStartedEvent event is used to make sure that the Get() call will
  // acquire the lock before the Reset() call acquires the lock.
  if (g_hGETStartedEvent) {
    TRACE(_T("InetBgDl: waiting on g_hGETStartedEvent\n"));
    WaitForSingleObject(g_hGETStartedEvent, INFINITE);
    CloseHandle(g_hGETStartedEvent);
    g_hGETStartedEvent = NULL;
  }

  TaskLock_AcquireExclusive();
#ifndef ONELOCKTORULETHEMALL
  StatsLock_AcquireExclusive();
#endif
  g_FilesTotal = 0; // This causes the Task thread to exit the transfer loop
  if (g_hThread)
  {
    TRACE(_T("InetBgDl: waiting on g_hThread\n"));
    if (WAIT_OBJECT_0 != WaitForSingleObject(g_hThread, 5 * 1000))
    {
      TRACE(_T("InetBgDl: terminating g_hThread\n"));
      // Suspend the thread so that it's not still trying to use these handles
      // that we're about to close out from under it.
      SuspendThread(g_hThread);
      if (g_hInetFile) {
        InternetCloseHandle(g_hInetFile);
        g_hInetFile = nullptr;
      }
      if (g_hInetSes) {
        InternetCloseHandle(g_hInetSes);
        g_hInetSes = nullptr;
      }
      TerminateThread(g_hThread, ERROR_OPERATION_ABORTED);
    }
    CloseHandle(g_hThread);
    g_hThread = NULL;
  }
  g_FilesTotal = 0;
  g_FilesCompleted = 0;
  g_Status = STATUS_INITIAL;
#ifndef ONELOCKTORULETHEMALL
  StatsLock_ReleaseExclusive();
#endif
  for (NSIS::stack_t*pTmpTast,*pTask = g_pLocations; pTask ;)
  {
    pTmpTast = pTask;
    pTask = pTask->next;
    StackFreeItem(pTmpTast);
  }
  g_pLocations = NULL;
  TaskLock_ReleaseExclusive();
}

UINT_PTR __cdecl NSISPluginCallback(UINT Event)
{
  switch(Event)
  {
  case NSPIM_UNLOAD:
    Reset();
    break;
  }
  return NULL;
}

void __stdcall InetStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext,
                                  DWORD dwInternetStatus,
                                  LPVOID lpvStatusInformation,
                                  DWORD dwStatusInformationLength)
{
  if (dwInternetStatus == INTERNET_STATUS_NAME_RESOLVED) {
    // If we're in the process of being reset, don't try to update g_ServerIP;
    // there's no need for it, and Reset() will be holding the StatsLock, so
    // we'll hang here and block the reset if we try to acquire it.
    if (g_FilesTotal != 0) {
      // The documentation states the IP address is a PCTSTR but it is usually a
      // PCSTR and only sometimes a PCTSTR.
      StatsLock_AcquireExclusive();
      wsprintf(g_ServerIP, _T("%S"), lpvStatusInformation);
      if (lstrlen(g_ServerIP) == 1)
      {
        wsprintf(g_ServerIP, _T("%s"), lpvStatusInformation);
      }
      StatsLock_ReleaseExclusive();
    }
  }

#if defined(PLUGIN_DEBUG)
  switch (dwInternetStatus)
  {
    case INTERNET_STATUS_RESOLVING_NAME:
      TRACE(_T("InetBgDl: INTERNET_STATUS_RESOLVING_NAME (%d), name=%s\n"),
            dwStatusInformationLength, lpvStatusInformation);
      break;
    case INTERNET_STATUS_NAME_RESOLVED:
      TRACE(_T("InetBgDl: INTERNET_STATUS_NAME_RESOLVED (%d), resolved name=%s\n"),
            dwStatusInformationLength, g_ServerIP);
      break;
    case INTERNET_STATUS_CONNECTING_TO_SERVER:
      TRACE(_T("InetBgDl: INTERNET_STATUS_CONNECTING_TO_SERVER (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_CONNECTED_TO_SERVER:
      TRACE(_T("InetBgDl: INTERNET_STATUS_CONNECTED_TO_SERVER (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_SENDING_REQUEST:
      TRACE(_T("InetBgDl: INTERNET_STATUS_SENDING_REQUEST (%d)\n"),
               dwStatusInformationLength);
      break;
    case INTERNET_STATUS_REQUEST_SENT:
      TRACE(_T("InetBgDl: INTERNET_STATUS_REQUEST_SENT (%d), bytes sent=%d\n"),
             dwStatusInformationLength, lpvStatusInformation);
      break;
    case INTERNET_STATUS_RECEIVING_RESPONSE:
      TRACE(_T("InetBgDl: INTERNET_STATUS_RECEIVING_RESPONSE (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_RESPONSE_RECEIVED:
      TRACE(_T("InetBgDl: INTERNET_STATUS_RESPONSE_RECEIVED (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_CTL_RESPONSE_RECEIVED:
      TRACE(_T("InetBgDl: INTERNET_STATUS_CTL_RESPONSE_RECEIVED (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_PREFETCH:
      TRACE(_T("InetBgDl: INTERNET_STATUS_PREFETCH (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_CLOSING_CONNECTION:
      TRACE(_T("InetBgDl: INTERNET_STATUS_CLOSING_CONNECTION (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_CONNECTION_CLOSED:
      TRACE(_T("InetBgDl: INTERNET_STATUS_CONNECTION_CLOSED (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_HANDLE_CREATED:
      TRACE(_T("InetBgDl: INTERNET_STATUS_HANDLE_CREATED (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_HANDLE_CLOSING:
      TRACE(_T("InetBgDl: INTERNET_STATUS_HANDLE_CLOSING (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_DETECTING_PROXY:
      TRACE(_T("InetBgDl: INTERNET_STATUS_DETECTING_PROXY (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_REQUEST_COMPLETE:
      TRACE(_T("InetBgDl: INTERNET_STATUS_REQUEST_COMPLETE (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_REDIRECT:
      TRACE(_T("InetBgDl: INTERNET_STATUS_REDIRECT (%d), new url=%s\n"),
            dwStatusInformationLength, lpvStatusInformation);
      break;
    case INTERNET_STATUS_INTERMEDIATE_RESPONSE:
      TRACE(_T("InetBgDl: INTERNET_STATUS_INTERMEDIATE_RESPONSE (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_USER_INPUT_REQUIRED:
      TRACE(_T("InetBgDl: INTERNET_STATUS_USER_INPUT_REQUIRED (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_STATE_CHANGE:
      TRACE(_T("InetBgDl: INTERNET_STATUS_STATE_CHANGE (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_COOKIE_SENT:
      TRACE(_T("InetBgDl: INTERNET_STATUS_COOKIE_SENT (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_COOKIE_RECEIVED:
      TRACE(_T("InetBgDl: INTERNET_STATUS_COOKIE_RECEIVED (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_PRIVACY_IMPACTED:
      TRACE(_T("InetBgDl: INTERNET_STATUS_PRIVACY_IMPACTED (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_P3P_HEADER:
      TRACE(_T("InetBgDl: INTERNET_STATUS_P3P_HEADER (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_P3P_POLICYREF:
      TRACE(_T("InetBgDl: INTERNET_STATUS_P3P_POLICYREF (%d)\n"),
            dwStatusInformationLength);
      break;
    case INTERNET_STATUS_COOKIE_HISTORY:
      TRACE(_T("InetBgDl: INTERNET_STATUS_COOKIE_HISTORY (%d)\n"),
            dwStatusInformationLength);
      break;
    default:
      TRACE(_T("InetBgDl: Unknown Status %d\n"), dwInternetStatus);
      break;
  }
#endif
}

DWORD CALLBACK TaskThreadProc(LPVOID ThreadParam)
{
  NSIS::stack_t *pURL,*pFile;
  DWORD cbio = sizeof(DWORD);
  DWORD previouslyWritten = 0, writtenThisSession = 0;
  HANDLE hLocalFile;
  bool completedFile = false;
startnexttask:
  hLocalFile = INVALID_HANDLE_VALUE;
  pFile = NULL;
  TaskLock_AcquireExclusive();
  // Now that we've acquired the lock, we can set the event to indicate this.
  // SetEvent will likely never fail, but if it does we should set it to NULL
  // to avoid anyone waiting on it.
  if (!SetEvent(g_hGETStartedEvent)) {
    CloseHandle(g_hGETStartedEvent);
    g_hGETStartedEvent = NULL;
  }
  pURL = g_pLocations;
  if (pURL)
  {
    pFile = pURL->next;
    g_pLocations = pFile->next;
  }
#ifndef ONELOCKTORULETHEMALL
  StatsLock_AcquireExclusive();
#endif
  if (completedFile)
  {
    ++g_FilesCompleted;
  }
  completedFile = false;
  g_cbCurrXF = 0;
  g_cbCurrTot = FILESIZE_UNKNOWN;
  if (!pURL)
  {
    if (g_FilesTotal)
    {
      if (g_FilesTotal == g_FilesCompleted)
      {
        g_Status = STATUS_COMPLETEDALL;
      }
    }
    g_hThread = NULL;
  }
#ifndef ONELOCKTORULETHEMALL
  StatsLock_ReleaseExclusive();
#endif
  TaskLock_ReleaseExclusive();

  if (!pURL)
  {
    if (0)
    {
diegle:
      DWORD gle = GetLastError();
      //TODO? if (ERROR_INTERNET_EXTENDED_ERROR==gle) InternetGetLastResponseInfo(...)
      g_Status = STATUS_ERR_GETLASTERROR;
    }
die:
    if (g_hInetSes)
    {
      InternetCloseHandle(g_hInetSes);
      g_hInetSes = nullptr;
    }
    if (INVALID_HANDLE_VALUE != hLocalFile)
    {
      CloseHandle(hLocalFile);
    }
    StackFreeItem(pURL);
    StackFreeItem(pFile);
    return 0;
  }

  if (!g_hInetSes)
  {
    g_hInetSes = InternetOpen(USERAGENT, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if (!g_hInetSes)
    {
      TRACE(_T("InetBgDl: InternetOpen failed with gle=%u\n"),
            GetLastError());
      goto diegle;
    }
    InternetSetStatusCallback(g_hInetSes, (INTERNET_STATUS_CALLBACK)InetStatusCallback);

    //msdn.microsoft.com/library/default.asp?url=/workshop/components/offline/offline.asp#Supporting Offline Browsing in Applications and Components
    ULONG longOpt;
    DWORD cbio = sizeof(ULONG);
    if (InternetQueryOption(g_hInetSes, INTERNET_OPTION_CONNECTED_STATE, &longOpt, &cbio))
    {
      if (INTERNET_STATE_DISCONNECTED_BY_USER&longOpt)
      {
        INTERNET_CONNECTED_INFO ci = {INTERNET_STATE_CONNECTED, 0};
        InternetSetOption(g_hInetSes, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci));
      }
    }

    // Change the default connect timeout if specified.
    if(g_ConnectTimeout > 0)
    {
      InternetSetOption(g_hInetSes, INTERNET_OPTION_CONNECT_TIMEOUT,
                        &g_ConnectTimeout, sizeof(g_ConnectTimeout));
    }

    // Change the default receive timeout if specified.
    if (g_ReceiveTimeout)
    {
      InternetSetOption(g_hInetSes, INTERNET_OPTION_RECEIVE_TIMEOUT,
                        &g_ReceiveTimeout, sizeof(DWORD));
    }
  }

  DWORD ec = ERROR_SUCCESS;
  hLocalFile = CreateFile(pFile->text, GENERIC_READ | GENERIC_WRITE,
                          FILE_SHARE_READ | FILE_SHARE_DELETE,
                          NULL, OPEN_ALWAYS, 0, NULL);
  if (INVALID_HANDLE_VALUE == hLocalFile)
  {
    TRACE(_T("InetBgDl: CreateFile file handle invalid\n"));
    goto diegle;
  }
  if (GetLastError() == ERROR_ALREADY_EXISTS) {
    // Resuming a download that was started earlier and then aborted.
    previouslyWritten = GetFileSize(hLocalFile, NULL);
    g_cbCurrXF = previouslyWritten;
    SetFilePointer(hLocalFile, previouslyWritten, NULL, FILE_BEGIN);
  }

  const DWORD IOURedirFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |
                              INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS;
  const DWORD IOUCacheFlags = INTERNET_FLAG_RESYNCHRONIZE |
                              INTERNET_FLAG_NO_CACHE_WRITE |
                              INTERNET_FLAG_PRAGMA_NOCACHE |
                              INTERNET_FLAG_RELOAD;
  const DWORD IOUCookieFlags = INTERNET_FLAG_NO_COOKIES;
  DWORD IOUFlags = IOURedirFlags | IOUCacheFlags | IOUCookieFlags |
                   INTERNET_FLAG_NO_UI | INTERNET_FLAG_EXISTING_CONNECT;

  TCHAR *hostname = (TCHAR*) GlobalAlloc(GPTR, MAX_STRLEN * sizeof(TCHAR)),
        *urlpath = (TCHAR*) GlobalAlloc(GPTR, MAX_STRLEN * sizeof(TCHAR)),
        *extrainfo = (TCHAR*) GlobalAlloc(GPTR, MAX_STRLEN * sizeof(TCHAR));

  URL_COMPONENTS uc = { sizeof(URL_COMPONENTS), NULL, 0, (INTERNET_SCHEME)0,
                        hostname, MAX_STRLEN, (INTERNET_PORT)0, NULL, 0,
                        NULL, 0, urlpath, MAX_STRLEN, extrainfo, MAX_STRLEN};
  uc.dwHostNameLength = uc.dwUrlPathLength = uc.dwExtraInfoLength = MAX_STRLEN;

  if (!InternetCrackUrl(pURL->text, 0, ICU_ESCAPE, &uc))
  {
    // Bad url or param passed in
    TRACE(_T("InetBgDl: InternetCrackUrl false with url=%s, gle=%u\n"),
          pURL->text, GetLastError());
    goto diegle;
  }

  TRACE(_T("InetBgDl: scheme_id=%d, hostname=%s, port=%d, urlpath=%s, extrainfo=%s\n"),
        uc.nScheme, hostname, uc.nPort, urlpath, extrainfo);

  // Only http and https are supported
  if (uc.nScheme != INTERNET_SCHEME_HTTP &&
      uc.nScheme != INTERNET_SCHEME_HTTPS)
  {
    TRACE(_T("InetBgDl: only http and https is supported, aborting...\n"));
    goto diegle;
  }

  // Tell the server to pick up wherever we left off.
  TCHAR headers[32];
  // We're skipping building the C runtime to keep the file size low, so we
  // can't use a normal string initialization because that would call memset.
  headers[0] = _T('\0');
  wsprintf(headers, _T("Range: bytes=%d-\r\n"), previouslyWritten);

  TRACE(_T("InetBgDl: calling InternetOpenUrl with url=%s\n"), pURL->text);
  g_hInetFile = InternetOpenUrl(g_hInetSes, pURL->text,
                                headers, -1, IOUFlags |
                                (uc.nScheme == INTERNET_SCHEME_HTTPS ?
                                 INTERNET_FLAG_SECURE : 0), 1);
  if (!g_hInetFile)
  {
    TRACE(_T("InetBgDl: InternetOpenUrl failed with gle=%u\n"),
          GetLastError());
    goto diegle;
  }

  // Get the file length via the Content-Length header
  FILESIZE_T cbThisFile;
  cbio = sizeof(cbThisFile);
  if (!HttpQueryInfo(g_hInetFile,
                     HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
                     &cbThisFile, &cbio, NULL))
  {
    cbThisFile = FILESIZE_UNKNOWN;
  }
  TRACE(_T("InetBgDl: file size=%d bytes\n"), cbThisFile);

  // Use a 4MiB read buffer for the connection.
  // Bigger buffers will be faster.
  // cbReadBufXF should be a multiple of g_cbBufXF.
  const UINT cbReadBufXF = 4194304;

  // Up the default internal buffer size from 4096 to internalReadBufferSize.
  DWORD internalReadBufferSize = cbReadBufXF;
  if (!InternetSetOption(g_hInetFile, INTERNET_OPTION_READ_BUFFER_SIZE,
                         &internalReadBufferSize, sizeof(DWORD)))
  {
    TRACE(_T("InetBgDl: InternetSetOption failed to set read buffer size to %u bytes, gle=%u\n"),
          internalReadBufferSize, GetLastError());

    // Maybe it's too big, try half of the optimal value.  If that fails just
    // use the default.
    internalReadBufferSize /= 2;
    if (!InternetSetOption(g_hInetFile, INTERNET_OPTION_READ_BUFFER_SIZE,
                           &internalReadBufferSize, sizeof(DWORD)))
    {
      TRACE(_T("InetBgDl: InternetSetOption failed to set read buffer size ") \
            _T("to %u bytes (using default read buffer size), gle=%u\n"),
            internalReadBufferSize, GetLastError());
    }
  }

  for(;;)
  {
    DWORD cbio = 0, cbXF = 0;
    BOOL retXF = InternetReadFile(g_hInetFile, g_bufXF, g_cbBufXF, &cbio);
    if (!retXF)
    {
      ec = GetLastError();
      TRACE(_T("InetBgDl: InternetReadFile failed, gle=%u\n"), ec);
      if (ERROR_INTERNET_CONNECTION_ABORTED == ec ||
          ERROR_INTERNET_CONNECTION_RESET == ec)
      {
        ec = ERROR_BROKEN_PIPE;
      }
      break;
    }

    if (0 == cbio)
    {
      ASSERT(ERROR_SUCCESS == ec);
      // EOF or broken connection?
      // TODO: Can InternetQueryDataAvailable detect this?

      TRACE(_T("InetBgDl: InternetReadFile true with 0 cbio, cbThisFile=%d, gle=%u\n"),
            cbThisFile, GetLastError());
      // If we haven't transferred all of the file, and we know how big the file
      // is, and we have no more data to read from the HTTP request, then set a
      // broken pipe error. Reading without StatsLock is ok in this thread.
      if (FILESIZE_UNKNOWN != cbThisFile && writtenThisSession != cbThisFile)
      {
        TRACE(_T("InetBgDl: expected Content-Length of %d bytes, ")
              _T("but transferred %d bytes\n"),
              cbThisFile, writtenThisSession);
        ec = ERROR_BROKEN_PIPE;
      }
      break;
    }

    // Check if we canceled the download
    if (0 == g_FilesTotal)
    {
      TRACE(_T("InetBgDl: 0 == g_FilesTotal, aborting transfer loop...\n"));
      ec = ERROR_CANCELLED;
      break;
    }

    cbXF = cbio;
    if (cbXF)
    {
      retXF = WriteFile(hLocalFile, g_bufXF, cbXF, &cbio, NULL);
      if (!retXF || cbXF != cbio)
      {
        ec = GetLastError();
        break;
      }

      StatsLock_AcquireExclusive();
      if (FILESIZE_UNKNOWN != cbThisFile) {
        g_cbCurrTot = cbThisFile;
      }
      writtenThisSession += cbXF;
      g_cbCurrXF += cbXF;
      StatsLock_ReleaseExclusive();
    }
  }

  TRACE(_T("InetBgDl: TaskThreadProc completed %s, ec=%u\n"), pURL->text, ec);
  InternetCloseHandle(g_hInetFile);
  g_hInetFile = nullptr;
  if (ERROR_SUCCESS == ec)
  {
    if (INVALID_HANDLE_VALUE != hLocalFile)
    {
      CloseHandle(hLocalFile);
      hLocalFile = INVALID_HANDLE_VALUE;
    }
    StackFreeItem(pURL);
    StackFreeItem(pFile);
    ++completedFile;
  }
  else if (ERROR_BROKEN_PIPE == ec)
  {
    g_Status = STATUS_ERR_CONNECTION_LOST;
    goto die;
  }
  else
  {
    TRACE(_T("InetBgDl: failed with ec=%u\n"), ec);
    SetLastError(ec);
    goto diegle;
  }
  goto startnexttask;
}

NSISPIEXPORTFUNC Get(HWND hwndNSIS, UINT N_CCH, TCHAR*N_Vars, NSIS::stack_t**ppST, NSIS::xparams_t*pX)
{
  pX->RegisterPluginCallback(g_hInst, NSISPluginCallback);
  for (;;)
  {
    NSIS::stack_t*pURL = StackPopItem(ppST);
    if (!pURL)
    {
      break;
    }

    if (lstrcmpi(pURL->text, _T("/connecttimeout")) == 0)
    {
      NSIS::stack_t*pConnectTimeout = StackPopItem(ppST);
      g_ConnectTimeout = MyTStrToL(pConnectTimeout->text) * 1000;
      continue;
    }
    else if (lstrcmpi(pURL->text, _T("/receivetimeout")) == 0)
    {
      NSIS::stack_t*pReceiveTimeout = StackPopItem(ppST);
      g_ReceiveTimeout = MyTStrToL(pReceiveTimeout->text) * 1000;
      continue;
    }
    else if (lstrcmpi(pURL->text, _T("/reset")) == 0)
    {
      StackFreeItem(pURL);
      Reset();
      continue;
    }
    else if (lstrcmpi(pURL->text, _T("/end")) == 0)
    {
freeurlandexit:
      StackFreeItem(pURL);
      break;
    }

    NSIS::stack_t*pFile = StackPopItem(ppST);
    if (!pFile)
    {
      goto freeurlandexit;
    }

    TaskLock_AcquireExclusive();

    pFile->next = NULL;
    pURL->next = pFile;
    NSIS::stack_t*pTasksTail = g_pLocations;
    while(pTasksTail && pTasksTail->next) pTasksTail = pTasksTail->next;
    if (pTasksTail)
    {
      pTasksTail->next = pURL;
    }
    else
    {
      g_pLocations = pURL;
    }

    if (!g_hThread)
    {
      DWORD tid;
      if (g_hGETStartedEvent) {
        CloseHandle(g_hGETStartedEvent);
      }
      g_hGETStartedEvent = CreateEvent(NULL, TRUEFALSE, NULL);
      g_hThread = CreateThread(NULL, 0, TaskThreadProc, NULL, 0, &tid);
    }

    if (!g_hThread)
    {
      goto freeurlandexit;
    }

#ifndef ONELOCKTORULETHEMALL
    StatsLock_AcquireExclusive();
#endif
    ++g_FilesTotal;
#ifndef ONELOCKTORULETHEMALL
    StatsLock_ReleaseExclusive();
#endif
    TaskLock_ReleaseExclusive();
  }
}

NSISPIEXPORTFUNC GetStats(HWND hwndNSIS, UINT N_CCH, TCHAR*N_Vars, NSIS::stack_t**ppST, NSIS::xparams_t*pX)
{
  NSISPI_INITGLOBALS(N_CCH, N_Vars);
  StatsLock_AcquireShared();
  NSIS_SetRegUINT(0, g_Status);
  NSIS_SetRegUINT(1, g_FilesCompleted);
  NSIS_SetRegUINT(2, g_FilesTotal - g_FilesCompleted);
  NSIS_SetRegUINT(3, g_cbCurrXF);
  NSIS_SetRegStrEmpty(4);
  if (FILESIZE_UNKNOWN != g_cbCurrTot)
  {
    NSIS_SetRegUINT(4, g_cbCurrTot);
  }
  NSIS_SetRegStr(5, g_ServerIP);
  StatsLock_ReleaseShared();
}

BOOL WINAPI DllMain(HINSTANCE hInst, ULONG Reason, LPVOID pCtx)
{
  if (DLL_PROCESS_ATTACH==Reason)
  {
    g_hInst=hInst;
    InitializeCriticalSection(&g_CritLock);
  }
  return TRUE;
}

Messung V0.5
C=93 H=83 G=87

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.