void StatusCallback(void *param) { #ifdef USE_VLD VLDEnable(); #endif HWND hwnd = (HWND)param; plString statusUrl = GetServerStatusUrl(); CURL *hCurl = curl_easy_init(); // For reporting errors char curlError[CURL_ERROR_SIZE]; curl_easy_setopt(hCurl, CURLOPT_ERRORBUFFER, curlError); while(s_loginDlgRunning) { curl_easy_setopt(hCurl, CURLOPT_URL, statusUrl.c_str()); curl_easy_setopt(hCurl, CURLOPT_USERAGENT, "UruClient/1.0"); curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, &CurlCallback); curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, param); if (!statusUrl.IsEmpty() && curl_easy_perform(hCurl) != 0) // only perform request if there's actually a URL set PostMessage(hwnd, WM_USER_SETSTATUSMSG, 0, (LPARAM) curlError); for(unsigned i = 0; i < UPDATE_STATUSMSG_SECONDS && s_loginDlgRunning; ++i) { Sleep(1000); } } curl_easy_cleanup(hCurl); s_statusEvent.Signal(); // Signal the semaphore }
hsError pfPatcherWorker::Run() { // So here's the rub: // We have one or many manifests in the fRequests deque. We begin issuing those requests one-by one, starting here. // As we receive the answer, the NetCli thread populates fQueuedFiles and pings the fFileSignal semaphore, then issues the next request... // In this non-UI/non-Net thread, we do the stutter-prone/time-consuming IO/hashing operations. (Typically, the UI thread == Net thread) // As we find files that need updating, we add them to fRequests. // If there is no net request from ME when we find a file, we issue the request // Once a file is downloaded, the next request is issued. // When there are no files in my deque and no requests in my deque, we exit without errors. PatcherLogWhite("--- Patch Started (%i requests) ---", fRequests.size()); fStarted = true; IssueRequest(); // Now, work until we're done processing files do { fFileSignal.Wait(); hsTempMutexLock fileLock(fFileMut); if (!fQueuedFiles.empty()) { ProcessFile(); continue; } // This makes sure both queues are empty before exiting. if (!fRequestActive) if(!IssueRequest()) break; } while (fStarted); EndPatch(kNetSuccess); return hsOK; }
bool pfPatcherWorker::IssueRequest() { hsTempMutexLock lock(fRequestMut); if (fRequests.empty()) { fRequestActive = false; fFileSignal.Signal(); // make sure the patch thread doesn't deadlock! return false; } else fRequestActive = true; const Request& req = fRequests.front(); switch (req.fType) { case Request::kFile: req.fStream->Begin(); if (fFileBeginDownload) fFileBeginDownload(req.fStream->GetFileName()); NetCliFileDownloadRequest(req.fName, req.fStream, IFileThingDownloadCB, this); break; case Request::kManifest: NetCliFileManifestRequest(IFileManifestDownloadCB, this, req.fName.ToWchar()); break; case Request::kSecurePreloader: // so, yeah, this is usually the "SecurePreloader" manifest on the file server... // except on legacy servers, this may not exist, so we need to fall back without nuking everything! NetCliFileManifestRequest(IPreloaderManifestDownloadCB, this, req.fName.ToWchar()); break; case Request::kAuthFile: // ffffffuuuuuu req.fStream->Begin(); if (fFileBeginDownload) fFileBeginDownload(req.fStream->GetFileName()); NetCliAuthFileRequest(req.fName, req.fStream, IAuthThingDownloadCB, this); break; case Request::kPythonList: NetCliAuthFileListRequest(L"Python", L"pak", IGotAuthFileList, this); break; case Request::kSdlList: NetCliAuthFileListRequest(L"SDL", L"sdl", IGotAuthFileList, this); break; DEFAULT_FATAL(req.fType); } fRequests.pop_front(); return true; }
void pfPatcherWorker::EndPatch(ENetError result, const plString& msg) { // Guard against multiple calls if (fStarted) { // Send end status if (fOnComplete) fOnComplete(result, msg); // yay log hax if (IS_NET_SUCCESS(result)) PatcherLogWhite("--- Patch Complete ---"); else { PatcherLogRed("\tNetwork Error: %S", NetErrorToString(result)); PatcherLogWhite("--- Patch Killed by Error ---"); } } fStarted = false; fFileSignal.Signal(); }
BOOL CALLBACK UruLoginDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { static LoginDialogParam* pLoginParam; static bool showAuthFailed = false; switch( uMsg ) { case WM_INITDIALOG: { s_loginDlgRunning = true; _beginthread(StatusCallback, 0, hwndDlg); pLoginParam = (LoginDialogParam*)lParam; SetWindowText(hwndDlg, "Login"); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(gHInst, MAKEINTRESOURCE(IDI_ICON_DIRT))); EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); SetDlgItemText(hwndDlg, IDC_URULOGIN_USERNAME, pLoginParam->username); CheckDlgButton(hwndDlg, IDC_URULOGIN_REMEMBERPASS, pLoginParam->remember ? BST_CHECKED : BST_UNCHECKED); if (pLoginParam->remember) SetDlgItemText(hwndDlg, IDC_URULOGIN_PASSWORD, FAKE_PASS_STRING); SetFocus(GetDlgItem(hwndDlg, pLoginParam->focus)); if (IS_NET_ERROR(pLoginParam->authError)) { showAuthFailed = true; } SendMessage(GetDlgItem(hwndDlg, IDC_PRODUCTSTRING), WM_SETTEXT, 0, (LPARAM)plProduct::ProductString().c_str()); for (int i = 0; i < plLocalization::GetNumLocales(); i++) { SendMessage(GetDlgItem(hwndDlg, IDC_LANGUAGE), CB_ADDSTRING, 0, (LPARAM)plLocalization::GetLanguageName((plLocalization::Language)i)); } SendMessage(GetDlgItem(hwndDlg, IDC_LANGUAGE), CB_SETCURSEL, (WPARAM)plLocalization::GetLanguage(), 0); SetTimer(hwndDlg, AUTH_LOGIN_TIMER, 10, NULL); return FALSE; } case WM_USER_SETSTATUSMSG: SendMessage(GetDlgItem(hwndDlg, IDC_STATUS_TEXT), WM_SETTEXT, 0, lParam); return TRUE; case WM_DESTROY: { s_loginDlgRunning = false; s_statusEvent.Wait(); KillTimer(hwndDlg, AUTH_LOGIN_TIMER); return TRUE; } case WM_NCHITTEST: { SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, (LONG_PTR)HTCAPTION); return TRUE; } case WM_PAINT: { if (showAuthFailed) { SetTimer(hwndDlg, AUTH_FAILED_TIMER, 10, NULL); showAuthFailed = false; } return FALSE; } case WM_COMMAND: { if (HIWORD(wParam) == BN_CLICKED && (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)) { bool ok = (LOWORD(wParam) == IDOK); if (ok) { char password[kMaxPasswordLength]; GetDlgItemText(hwndDlg, IDC_URULOGIN_USERNAME, pLoginParam->username, kMaxAccountNameLength); GetDlgItemText(hwndDlg, IDC_URULOGIN_PASSWORD, password, kMaxPasswordLength); pLoginParam->remember = (IsDlgButtonChecked(hwndDlg, IDC_URULOGIN_REMEMBERPASS) == BST_CHECKED); plLocalization::Language new_language = (plLocalization::Language)SendMessage(GetDlgItem(hwndDlg, IDC_LANGUAGE), CB_GETCURSEL, 0, 0L); plLocalization::SetLanguage(new_language); SaveUserPass (pLoginParam, password); // Welcome to HACKland, population: Branan // The code to write general.ini really doesn't belong here, but it works... for now. // When general.ini gets expanded, this will need to find a proper home somewhere. { plFileName gipath = plFileName::Join(plFileSystem::GetInitPath(), "general.ini"); plString ini_str = plFormat("App.SetLanguage {}\n", plLocalization::GetLanguageName(new_language)); hsStream* gini = plEncryptedStream::OpenEncryptedFileWrite(gipath); gini->WriteString(ini_str); gini->Close(); delete gini; } memset(&pLoginParam->authError, 0, sizeof(pLoginParam->authError)); bool cancelled = AuthenticateNetClientComm(&pLoginParam->authError, hwndDlg); if (IS_NET_SUCCESS(pLoginParam->authError) && !cancelled) EndDialog(hwndDlg, ok); else { if (!cancelled) ::DialogBoxParam(gHInst, MAKEINTRESOURCE( IDD_AUTHFAILED ), hwndDlg, AuthFailedDialogProc, (LPARAM)pLoginParam); else { NetCommDisconnect(); } } } else EndDialog(hwndDlg, ok); return TRUE; } else if (HIWORD(wParam) == EN_CHANGE && LOWORD(wParam) == IDC_URULOGIN_USERNAME) { char username[kMaxAccountNameLength]; GetDlgItemText(hwndDlg, IDC_URULOGIN_USERNAME, username, kMaxAccountNameLength); if (StrLen(username) == 0) EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); else EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE); return TRUE; } else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_URULOGIN_NEWACCTLINK) { plString signupurl = GetServerSignupUrl(); ShellExecuteW(NULL, L"open", signupurl.ToWchar(), NULL, NULL, SW_SHOWNORMAL); return TRUE; } break; } case WM_TIMER: { switch(wParam) { case AUTH_FAILED_TIMER: KillTimer(hwndDlg, AUTH_FAILED_TIMER); ::DialogBoxParam(gHInst, MAKEINTRESOURCE( IDD_AUTHFAILED ), hwndDlg, AuthFailedDialogProc, (LPARAM)pLoginParam); return TRUE; case AUTH_LOGIN_TIMER: NetCommUpdate(); return TRUE; } return FALSE; } } return FALSE; }