/************************************************************************ MeOS - Orienteering Software Copyright (C) 2009-2019 Melin Software HB This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Melin Software HB - software@melin.nu - www.melin.nu Eksoppsvägen 16, SE-75646 UPPSALA, Sweden ************************************************************************/ #include "stdafx.h" #include "Download.h" #include #include "Localizer.h" #include "meos_util.h" #include "progress.h" #include "meosexception.h" #include #include #include #include #include #include #include #pragma comment(lib, "IPHLPAPI.lib") #define INET_ADDRSTRLEN 16 ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// Download::Download() { hThread = 0; doExit = false; //hProgress = NULL; fileno = 0; hInternet = NULL; hURL = NULL; bytesLoaded = 0; bytesToLoad = 1024; success = false; } Download::~Download() { shutDown(); endDownload(); if (hInternet) InternetCloseHandle(hInternet); } void __cdecl SUThread(void *ptr) { Download *dwl=(Download *)ptr; dwl->initThread(); } bool Download::createDownloadThread() { doExit=false; hThread=_beginthread(SUThread, 0, this); if (hThread==-1) { hThread=0; return false; } return true; } void Download::shutDown() { if (hThread) { doExit=true; int m=0; while(m<100 && hThread) { Sleep(0); Sleep(10); m++; } //If unsuccessful ending thread, do it violently if (hThread) { OutputDebugString(L"Terminate thread...\n"); TerminateThread(HANDLE(hThread), 0); CloseHandle(HANDLE(hThread)); } hThread=0; } } void Download::initThread() { int status = true; while(!doExit && status) { status = doDownload(); } hThread=0; } void Download::initInternet() { hInternet = InternetOpen(L"MeOS", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (hInternet==NULL) { DWORD ec = GetLastError(); wstring error = lang.tl(L"Error: X#" + getErrorMessage(ec)); throw meosException(error); } DWORD dwTimeOut = 180 * 1000; InternetSetOption(hInternet, INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeOut, sizeof(DWORD)); InternetSetOption(hInternet, INTERNET_OPTION_SEND_TIMEOUT, &dwTimeOut, sizeof(DWORD)); } void Download::downloadFile(const wstring &url, const wstring &file, const vector< pair > &headers) { if (hURL || !hInternet) throw std::exception("Not inititialized"); success = false; wstring hdr; wstring row; for (size_t k = 0; k= 400) { char bf[256]; switch (dwStatus) { case HTTP_STATUS_BAD_REQUEST: sprintf_s(bf, "HTTP Error 400: The request could not be processed by the server due to invalid syntax."); break; case HTTP_STATUS_DENIED: sprintf_s(bf, "HTTP Error 401: The requested resource requires user authentication."); break; case HTTP_STATUS_FORBIDDEN: sprintf_s(bf, "HTTP Error 403: Åtkomst nekad (access is denied)."); break; case HTTP_STATUS_NOT_FOUND: sprintf_s(bf, "HTTP Error 404: Resursen kunde ej hittas (not found)."); break; case HTTP_STATUS_NOT_SUPPORTED: sprintf_s(bf, "HTTP Error 501: Förfrågan stöds ej (not supported)."); break; case HTTP_STATUS_SERVER_ERROR: sprintf_s(bf, "HTTP Error 500: Internt serverfel (server error)."); break; default: sprintf_s(bf, "HTTP Status Error %d", dwStatus); } throw dwException(bf, dwStatus); } } fileno=_wopen(file.c_str(), O_BINARY|O_CREAT|O_WRONLY|O_TRUNC, S_IREAD|S_IWRITE); if (fileno==-1) { fileno=0; endDownload(); wchar_t bf[256]; swprintf_s(bf, L"Error opening '%s' for writing", file.c_str()); throw meosException(bf); } bytesLoaded = 0; return; } void Download::endDownload() { if (hURL && hInternet) { InternetCloseHandle(hURL); hURL=NULL; } if (fileno) { _close(fileno); fileno=0; } } bool Download::doDownload() { if (hURL && hInternet) { char buffer[512]; DWORD bRead; if (InternetReadFile(hURL, buffer, 512, &bRead)) { //Success! if (bRead==0) { //EOF success=true; endDownload(); } else{ if (_write(fileno, buffer, bRead) != int(bRead)) { endDownload(); return false; } bytesLoaded+=bRead; return true; } } } return false; } void Download::setBytesToDownload(DWORD btd) { bytesToLoad = btd; } bool Download::isWorking() { return hThread!=0; } bool Download::successful() { return success; } void Download::postFile(const wstring &url, const wstring &file, const wstring &fileOut, const vector< pair > &headers, ProgressWindow &pw) { SetLastError(0); DWORD_PTR dw = 0; URL_COMPONENTS uc; memset(&uc, 0, sizeof(uc)); uc.dwStructSize = sizeof(uc); wchar_t host[128]; wchar_t path[128]; wchar_t extra[256]; uc.lpszExtraInfo = extra; uc.dwExtraInfoLength = sizeof(extra); uc.lpszHostName = host; uc.dwHostNameLength = sizeof(host); uc.lpszUrlPath = path; uc.dwUrlPathLength = sizeof(path); InternetCrackUrl(url.c_str(), url.length(), ICU_ESCAPE, &uc); int port = INTERNET_DEFAULT_HTTP_PORT; bool https = uc.nScheme == INTERNET_SCHEME_HTTPS; if (https) port = INTERNET_DEFAULT_HTTPS_PORT; else if (uc.nPort>0) port = uc.nPort; HINTERNET hConnect = InternetConnect(hInternet, host, port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, dw); bool vsuccess = false; int errorCode = 0; try { vsuccess = httpSendReqEx(hConnect, https, path, headers, file, fileOut, pw, errorCode); } catch (std::exception &) { InternetCloseHandle(hConnect); throw; } InternetCloseHandle(hConnect); if (!vsuccess) { if (errorCode != 0) errorCode = GetLastError(); wstring error = errorCode != 0 ? getErrorMessage(errorCode) : L""; if (error.empty()) error = L"Ett okänt fel inträffade."; throw meosException(error); } } bool Download::httpSendReqEx(HINTERNET hConnect, bool https, const wstring &dest, const vector< pair > &headers, const wstring &upFile, const wstring &outFile, ProgressWindow &pw, int &errorCode) const { errorCode = 0; INTERNET_BUFFERS BufferIn; memset(&BufferIn, 0, sizeof(BufferIn)); BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS ); TCHAR szAccept[] = L"*/*"; LPCTSTR AcceptTypes[2] = { 0, 0 }; AcceptTypes[0] = szAccept; DWORD flags = INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_KEEP_CONNECTION; if (https) flags |= INTERNET_FLAG_SECURE; HINTERNET hRequest = HttpOpenRequest (hConnect, L"POST", dest.c_str(), HTTP_VERSION, NULL, AcceptTypes, flags, 0); DWORD dwBytesRead = 0; DWORD dwBytesWritten = 0; BYTE pBuffer[4*1024]; // Read from file in 4K chunks wstring hdr; for (size_t k = 0; k0) { HANDLE hFile = CreateFile(upFile.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == HANDLE(-1)) return false; BufferIn.dwBufferTotal = GetFileSize (hFile, NULL); BufferIn.dwHeadersLength = hdr.length(); BufferIn.lpcszHeader = hdr.c_str(); double totSize = BufferIn.dwBufferTotal; if (!HttpSendRequestEx( hRequest, &BufferIn, NULL, 0, 0)) { CloseHandle(hFile); InternetCloseHandle(hRequest); return false; } DWORD sum = 0; do { if (!ReadFile (hFile, pBuffer, sizeof(pBuffer), &dwBytesRead, NULL)) { errorCode = GetLastError(); CloseHandle(hFile); InternetCloseHandle(hRequest); return false; } if (dwBytesRead > 0) { if (!InternetWriteFile(hRequest, pBuffer, dwBytesRead, &dwBytesWritten)) { errorCode = GetLastError(); CloseHandle(hFile); InternetCloseHandle(hRequest); return false; } } sum += dwBytesWritten; try { pw.setProgress(int(1000 * double(sum) / totSize)); } catch (std::exception &) { CloseHandle(hFile); InternetCloseHandle(hRequest); throw; } } while (dwBytesRead == sizeof(pBuffer)) ; CloseHandle(hFile); if (!HttpEndRequest(hRequest, NULL, 0, 0)) { DWORD error = GetLastError(); errorCode = error; if (error == ERROR_INTERNET_FORCE_RETRY) retry--; else { InternetCloseHandle(hRequest); if (error == ERROR_INTERNET_TIMEOUT) { throw std::exception("Fick inget svar i tid (ERROR_INTERNET_TIMEOUT)"); } else if (error == ERROR_INTERNET_CONNECTION_RESET) { throw std::exception("Inget svar (ERROR_INTERNET_CONNECTION_RESET)"); } return false; } } else retry = 0; // Done } DWORD dwStatus = 0; DWORD dwBufLen = sizeof(dwStatus); int vsuccess = HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwStatus, &dwBufLen, 0); if (vsuccess) { if (dwStatus >= 400) { char bf[256]; switch (dwStatus) { case HTTP_STATUS_BAD_REQUEST: sprintf_s(bf, "HTTP Error 400: The request could not be processed by the server due to invalid syntax."); break; case HTTP_STATUS_DENIED: sprintf_s(bf, "HTTP Error 401: The requested resource requires user authentication."); break; case HTTP_STATUS_FORBIDDEN: sprintf_s(bf, "HTTP Error 403: Åtkomst nekad (access is denied)."); break; case HTTP_STATUS_NOT_FOUND: sprintf_s(bf, "HTTP Error 404: Resursen kunde ej hittas (not found)."); break; case HTTP_STATUS_NOT_SUPPORTED: sprintf_s(bf, "HTTP Error 501: Förfrågan stöds ej (not supported)."); break; case HTTP_STATUS_SERVER_ERROR: sprintf_s(bf, "HTTP Error 500: Internt serverfel (server error)."); break; default: sprintf_s(bf, "HTTP Status Error %d", dwStatus); } throw dwException(bf, dwStatus); } } int rfileno = _wopen(outFile.c_str(), O_BINARY|O_CREAT|O_WRONLY|O_TRUNC, S_IREAD|S_IWRITE); do { dwBytesRead=0; if (InternetReadFile(hRequest, pBuffer, sizeof(pBuffer)-1, &dwBytesRead)) { _write(rfileno, pBuffer, dwBytesRead); } } while(dwBytesRead>0); _close(rfileno); InternetCloseHandle(hRequest); return true; } void ListIpAddresses(vector& ipAddrs) { ipAddrs.clear(); IP_ADAPTER_ADDRESSES* adapter_addresses(NULL); IP_ADAPTER_ADDRESSES* adapter(NULL); const int KB = 1024; // Start with a 16 KB buffer and resize if needed - // multiple attempts in case interfaces change while // we are in the middle of querying them. DWORD adapter_addresses_buffer_size = 16 * 1024; for (int attempts = 0; attempts != 3; ++attempts) { adapter_addresses = (IP_ADAPTER_ADDRESSES*)malloc(adapter_addresses_buffer_size); assert(adapter_addresses); DWORD error = ::GetAdaptersAddresses( AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, NULL, adapter_addresses, &adapter_addresses_buffer_size); if (ERROR_SUCCESS == error) { // We're done here, people! break; } else if (ERROR_BUFFER_OVERFLOW == error) { // Try again with the new size free(adapter_addresses); adapter_addresses = NULL; continue; } else { // Unexpected error code - log and throw free(adapter_addresses); adapter_addresses = NULL; return; } } // Iterate through all of the adapters for (adapter = adapter_addresses; NULL != adapter; adapter = adapter->Next) { // Skip loopback adapters if (IF_TYPE_SOFTWARE_LOOPBACK == adapter->IfType) { continue; } // Parse all IPv4 and IPv6 addresses for ( IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress; NULL != address; address = address->Next) { auto family = address->Address.lpSockaddr->sa_family; if (AF_INET == family) { // IPv4 SOCKADDR_IN* ipv4 = reinterpret_cast(address->Address.lpSockaddr); char str_buffer[INET_ADDRSTRLEN] = { 0 }; //inet_ntop(AF_INET, &(ipv4->sin_addr), str_buffer, INET_ADDRSTRLEN); auto &id = ipv4->sin_addr.S_un.S_un_b; if (id.s_b1 == 169 && id.s_b2 == 254) continue; // Not usable sprintf_s(str_buffer, "%u.%u.%u.%u", id.s_b1, id.s_b2, id.s_b3, id.s_b4); ipAddrs.emplace_back(str_buffer); } else if (AF_INET6 == family) {/* // IPv6 SOCKADDR_IN6* ipv6 = reinterpret_cast(address->Address.lpSockaddr); char str_buffer[INET6_ADDRSTRLEN] = { 0 }; inet_ntop(AF_INET6, &(ipv6->sin6_addr), str_buffer, INET6_ADDRSTRLEN); std::string ipv6_str(str_buffer); // Detect and skip non-external addresses bool is_link_local(false); bool is_special_use(false); if (0 == ipv6_str.find("fe")) { char c = ipv6_str[2]; if (c == '8' || c == '9' || c == 'a' || c == 'b') { is_link_local = true; } } else if (0 == ipv6_str.find("2001:0:")) { is_special_use = true; } if (!(is_link_local || is_special_use)) { ipAddrs.mIpv6.push_back(ipv6_str); }*/ } else { // Skip all other types of addresses continue; } } } // Cleanup free(adapter_addresses); adapter_addresses = NULL; }