VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/HostUpdateImpl.cpp@ 85728

Last change on this file since 85728 was 85728, checked in by vboxsync, 5 years ago

Main/HostUpdateImpl.cpp: platformInfo should return Utf8Str and the strUserAgent variable should be Utf8Str rather than Bstr. Otherwise we end up with several unnecessary conversions between Bstr and Utf8Str, which is a complete waste of time. bugref:7983

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.4 KB
Line 
1/* $Id: */
2/** @file
3 * IHostUpdate COM class implementations.
4 */
5
6/*
7 * Copyright (C) 2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19#define LOG_GROUP LOG_GROUP_MAIN_HOSTUPDATE
20
21#include <iprt/cpp/utils.h>
22#include <iprt/param.h>
23#include <iprt/path.h>
24#include <iprt/http.h>
25#include <iprt/system.h>
26#include <iprt/message.h>
27#include <iprt/pipe.h>
28#include <iprt/env.h>
29#include <iprt/process.h>
30#include <iprt/assert.h>
31#include <iprt/err.h>
32#include <iprt/stream.h>
33#include <iprt/time.h>
34#include <VBox/com/defs.h>
35#include <VBox/version.h>
36
37#include "HostImpl.h"
38#include "HostUpdateImpl.h"
39#include "ProgressImpl.h"
40#include "AutoCaller.h"
41#include "LoggingNew.h"
42#include "VirtualBoxImpl.h"
43#include "ThreadTask.h"
44#include "SystemPropertiesImpl.h"
45#include "VirtualBoxBase.h"
46
47
48////////////////////////////////////////////////////////////////////////////////
49//
50// HostUpdate private data definition
51//
52////////////////////////////////////////////////////////////////////////////////
53
54
55class HostUpdate::UpdateCheckTask : public ThreadTask
56{
57public:
58 UpdateCheckTask(UpdateCheckType_T aCheckType, HostUpdate *aThat, Progress *aProgress)
59 : m_checkType(aCheckType)
60 , m_pHostUpdate(aThat)
61 , m_ptrProgress(aProgress)
62 , m_rc(S_OK)
63 {
64 m_strTaskName = "UpdateCheckTask";
65 }
66 ~UpdateCheckTask() { }
67
68private:
69 void handler();
70
71 UpdateCheckType_T m_checkType;
72 HostUpdate *m_pHostUpdate;
73
74 /** Smart pointer to the progress object for this job. */
75 ComObjPtr<Progress> m_ptrProgress;
76 HRESULT m_rc; /**< Not really used for anything, at the moment. */
77
78 friend class HostUpdate; // allow member functions access to private data
79};
80
81/* static */
82void HostUpdate::UpdateCheckTask::handler()
83{
84 HostUpdate *pHostUpdate = this->m_pHostUpdate;
85
86 LogFlowFuncEnter();
87 LogFlowFunc(("HostUpdate %p\n", pHostUpdate));
88
89 HRESULT rc = pHostUpdate->i_updateCheckTask(this);
90
91 LogFlowFunc(("rc=%Rhrc\n", rc)); NOREF(rc);
92 LogFlowFuncLeave();
93}
94
95/* static */
96Utf8Str HostUpdate::platformInfo()
97{
98 /* Prepare platform report: */
99 Utf8Str strPlatform;
100
101#if defined (RT_OS_WINDOWS)
102 strPlatform = "win";
103#elif defined (RT_OS_LINUX)
104 strPlatform = "linux";
105#elif defined (RT_OS_DARWIN)
106 strPlatform = "macosx";
107#elif defined (RT_OS_OS2)
108 strPlatform = "os2";
109#elif defined (RT_OS_FREEBSD)
110 strPlatform = "freebsd";
111#elif defined (RT_OS_SOLARIS)
112 strPlatform = "solaris";
113#else
114 strPlatform = "unknown";
115#endif
116
117 /* The format is <system>.<bitness>: */
118 strPlatform.appendPrintf(".%lu", ARCH_BITS);
119
120 /* Add more system information: */
121 int vrc;
122#ifdef RT_OS_LINUX
123 // WORKAROUND:
124 // On Linux we try to generate information using script first of all..
125
126 /* Get script path: */
127 char szAppPrivPath[RTPATH_MAX];
128 vrc = RTPathAppPrivateNoArch(szAppPrivPath, sizeof(szAppPrivPath));
129 AssertRC(vrc);
130 if (RT_SUCCESS(vrc))
131 vrc = RTPathAppend(szAppPrivPath, sizeof(szAppPrivPath), "/VBoxSysInfo.sh");
132 AssertRC(vrc);
133 if (RT_SUCCESS(vrc))
134 {
135 RTPIPE hPipeR;
136 RTHANDLE hStdOutPipe;
137 hStdOutPipe.enmType = RTHANDLETYPE_PIPE;
138 vrc = RTPipeCreate(&hPipeR, &hStdOutPipe.u.hPipe, RTPIPE_C_INHERIT_WRITE);
139 AssertLogRelRC(vrc);
140
141 char const *szAppPrivArgs[2];
142 szAppPrivArgs[0] = szAppPrivPath;
143 szAppPrivArgs[1] = NULL;
144 RTPROCESS hProc = NIL_RTPROCESS;
145
146 /* Run script: */
147 vrc = RTProcCreateEx(szAppPrivPath, szAppPrivArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL /*phStdin*/, &hStdOutPipe,
148 NULL /*phStderr*/, NULL /*pszAsUser*/, NULL /*pszPassword*/, NULL /*pvExtraData*/, &hProc);
149
150 (void) RTPipeClose(hStdOutPipe.u.hPipe);
151 hStdOutPipe.u.hPipe = NIL_RTPIPE;
152
153 if (RT_SUCCESS(vrc))
154 {
155 RTPROCSTATUS ProcStatus;
156 size_t cbStdOutBuf = 0;
157 size_t offStdOutBuf = 0;
158 char *pszStdOutBuf = NULL;
159 do
160 {
161 if (hPipeR != NIL_RTPIPE)
162 {
163 char achBuf[1024];
164 size_t cbRead;
165 vrc = RTPipeReadBlocking(hPipeR, achBuf, sizeof(achBuf), &cbRead);
166 if (RT_SUCCESS(vrc))
167 {
168 /* grow the buffer? */
169 size_t cbBufReq = offStdOutBuf + cbRead + 1;
170 if ( cbBufReq > cbStdOutBuf
171 && cbBufReq < _256K)
172 {
173 size_t cbNew = RT_ALIGN_Z(cbBufReq, 16); // 1024
174 void *pvNew = RTMemRealloc(pszStdOutBuf, cbNew);
175 if (pvNew)
176 {
177 pszStdOutBuf = (char *)pvNew;
178 cbStdOutBuf = cbNew;
179 }
180 }
181
182 /* append if we've got room. */
183 if (cbBufReq <= cbStdOutBuf)
184 {
185 (void) memcpy(&pszStdOutBuf[offStdOutBuf], achBuf, cbRead);
186 offStdOutBuf = offStdOutBuf + cbRead;
187 pszStdOutBuf[offStdOutBuf] = '\0';
188 }
189 }
190 else
191 {
192 AssertLogRelMsg(vrc == VERR_BROKEN_PIPE, ("%Rrc\n", vrc));
193 RTPipeClose(hPipeR);
194 hPipeR = NIL_RTPIPE;
195 }
196 }
197
198 /*
199 * Service the process. Block if we have no pipe.
200 */
201 if (hProc != NIL_RTPROCESS)
202 {
203 vrc = RTProcWait(hProc,
204 hPipeR == NIL_RTPIPE ? RTPROCWAIT_FLAGS_BLOCK : RTPROCWAIT_FLAGS_NOBLOCK,
205 &ProcStatus);
206 if (RT_SUCCESS(vrc))
207 hProc = NIL_RTPROCESS;
208 else
209 AssertLogRelMsgStmt(vrc == VERR_PROCESS_RUNNING, ("%Rrc\n", vrc), hProc = NIL_RTPROCESS);
210 }
211 } while ( hPipeR != NIL_RTPIPE
212 || hProc != NIL_RTPROCESS);
213
214 if ( ProcStatus.enmReason == RTPROCEXITREASON_NORMAL
215 && ProcStatus.iStatus == 0) {
216 pszStdOutBuf[offStdOutBuf-1] = '\0'; // remove trailing newline
217 Utf8Str pszStdOutBufUTF8(pszStdOutBuf);
218 strPlatform.appendPrintf(" [%s]", pszStdOutBufUTF8.strip().c_str());
219 // For testing, here is some sample output:
220 //strPlatform.appendPrintf(" [Distribution: Redhat | Version: 7.6.1810 | Kernel: Linux version 3.10.0-952.27.2.el7.x86_64 (gcc version 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) ) #1 SMP Mon Jul 29 17:46:05 UTC 2019]");
221 }
222 }
223 else
224 vrc = VERR_TRY_AGAIN; /* (take the fallback path) */
225 }
226
227 LogRelFunc(("strPlatform (Linux) = %s\n", strPlatform.c_str()));
228
229 if (RT_FAILURE(vrc))
230#endif /* RT_OS_LINUX */
231 {
232 /* Use RTSystemQueryOSInfo: */
233 char szTmp[256];
234
235 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
236 if ((RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) && szTmp[0] != '\0')
237 strPlatform.appendPrintf(" [Product: %s", szTmp);
238
239 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
240 if ((RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) && szTmp[0] != '\0')
241 strPlatform.appendPrintf(" %sRelease: %s", strlen(szTmp) == 0 ? "[" : "| ", szTmp);
242
243 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
244 if ((RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) && szTmp[0] != '\0')
245 strPlatform.appendPrintf(" %sVersion: %s", strlen(szTmp) == 0 ? "[" : "| ", szTmp);
246
247 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szTmp, sizeof(szTmp));
248 if ((RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) && szTmp[0] != '\0')
249 strPlatform.appendPrintf(" %sSP: %s]", strlen(szTmp) == 0 ? "[" : "| ", szTmp);
250
251 if (!strPlatform.endsWith("]"))
252 strPlatform.append("]");
253
254 LogRelFunc(("strPlatform = %s\n", strPlatform.c_str()));
255 }
256
257 return strPlatform;
258}
259
260/* static */
261HRESULT HostUpdate::i_checkForVBoxUpdate()
262{
263 HRESULT rc;
264
265 // Default to no update required
266 m_updateNeeded = FALSE;
267
268 // Following the sequence of steps in UIUpdateStepVirtualBox::sltStartStep()
269 // Build up our query URL starting with the URL basename
270 Bstr url("https://update.virtualbox.org/query.php/?");
271 Bstr platform;
272 rc = mVirtualBox->COMGETTER(PackageType)(platform.asOutParam());
273 if (FAILED(rc))
274 return setErrorVrc(rc, tr("%s: IVirtualBox::packageType() failed: %Rrc"), __FUNCTION__, rc);
275 url.appendPrintf("platform=%ls", platform.raw()); // e.g. SOLARIS_64BITS_GENERIC
276
277 // Get the complete current version string for the query URL
278 Bstr versionNormalized;
279 rc = mVirtualBox->COMGETTER(VersionNormalized)(versionNormalized.asOutParam());
280 if (FAILED(rc))
281 return setErrorVrc(rc, tr("%s: IVirtualBox::versionNormalized() failed: %Rrc"), __FUNCTION__, rc);
282 url.appendPrintf("&version=%ls", versionNormalized.raw()); // e.g. 6.1.1
283 // url.appendPrintf("&version=6.0.12"); // comment out previous line and uncomment this one for testing
284
285 ULONG revision;
286 rc = mVirtualBox->COMGETTER(Revision)(&revision);
287 if (FAILED(rc))
288 return setErrorVrc(rc, tr("%s: IVirtualBox::revision() failed: %Rrc"), __FUNCTION__, rc);
289 url.appendPrintf("_%ld", revision); // e.g. 135618
290
291 // acquire the System Properties interface
292 ComPtr<ISystemProperties> pSystemProperties;
293 rc = mVirtualBox->COMGETTER(SystemProperties)(pSystemProperties.asOutParam());
294 if (FAILED(rc))
295 return setErrorVrc(rc, tr("%s: IVirtualBox::systemProperties() failed: %Rrc"), __FUNCTION__, rc);
296
297 // Update the VBoxUpdate setting 'VBoxUpdateLastCheckDate'
298 RTTIME Time;
299 RTTIMESPEC TimeNow;
300 char szTimeStr[RTTIME_STR_LEN];
301
302 RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&TimeNow)), szTimeStr, sizeof(szTimeStr));
303 LogRelFunc(("VBox updating UpdateDate with TimeString = %s\n", szTimeStr));
304 rc = pSystemProperties->COMSETTER(VBoxUpdateLastCheckDate)(Bstr(szTimeStr).raw());
305 if (FAILED(rc))
306 return rc; // ISystemProperties::setLastCheckDate calls setError() on failure
307
308 // Update the queryURL and the VBoxUpdate setting 'VBoxUpdateCount'
309 ULONG cVBoxUpdateCount = 0;
310 rc = pSystemProperties->COMGETTER(VBoxUpdateCount)(&cVBoxUpdateCount);
311 if (FAILED(rc))
312 return setErrorVrc(rc, tr("%s: retrieving ISystemProperties::VBoxUpdateCount failed: %Rrc"), __FUNCTION__, rc);
313
314 cVBoxUpdateCount++;
315
316 rc = pSystemProperties->COMSETTER(VBoxUpdateCount)(cVBoxUpdateCount);
317 if (FAILED(rc))
318 return rc; // ISystemProperties::setVBoxUpdateCount calls setError() on failure
319 url.appendPrintf("&count=%lu", cVBoxUpdateCount);
320
321 // Update the query URL and the VBoxUpdate settings (if necessary) with the 'Target' information.
322 VBoxUpdateTarget_T enmTarget = VBoxUpdateTarget_Stable; // default branch is 'stable'
323 rc = pSystemProperties->COMGETTER(VBoxUpdateTarget)(&enmTarget);
324 if (FAILED(rc))
325 return setErrorVrc(rc, tr("%s: retrieving ISystemProperties::Target failed: %Rrc"), __FUNCTION__, rc);
326
327 switch (enmTarget)
328 {
329 case VBoxUpdateTarget_AllReleases:
330 url.appendPrintf("&branch=allrelease"); // query.php expects 'allrelease' and not 'allreleases'
331 break;
332 case VBoxUpdateTarget_WithBetas:
333 url.appendPrintf("&branch=withbetas");
334 break;
335 case VBoxUpdateTarget_Stable:
336 default:
337 url.appendPrintf("&branch=stable");
338 break;
339 }
340
341 rc = pSystemProperties->COMSETTER(VBoxUpdateTarget)(enmTarget);
342 if (FAILED(rc))
343 return rc; // ISystemProperties::setTarget calls setError() on failure
344
345 LogRelFunc(("VBox update URL = %s\n", Utf8Str(url).c_str()));
346
347 // Setup the User-Agent headers for the GET request
348 Bstr version;
349 rc = mVirtualBox->COMGETTER(Version)(version.asOutParam()); // e.g. 6.1.0_RC1
350 if (FAILED(rc))
351 return setErrorVrc(rc, tr("%s: IVirtualBox::version() failed: %Rrc"), __FUNCTION__, rc);
352
353 Utf8StrFmt const strUserAgent("VirtualBox %ls <%s>", version.raw(), HostUpdate::platformInfo().c_str());
354 LogRelFunc(("userAgent = %s\n", strUserAgent.c_str()));
355
356 RTHTTP hHttp = NIL_RTHTTP;
357 int vrc = RTHttpCreate(&hHttp);
358 if (RT_FAILURE(vrc))
359 return setErrorVrc(vrc, tr("%s: RTHttpCreate() failed: %Rrc"), __FUNCTION__, vrc);
360
361 /// @todo Are there any other headers needed to be added first via RTHttpSetHeaders()?
362 vrc = RTHttpAddHeader(hHttp, "User-Agent", strUserAgent.c_str(), strUserAgent.length(), RTHTTPADDHDR_F_BACK);
363 if (RT_FAILURE(vrc))
364 return setErrorVrc(vrc, tr("%s: RTHttpAddHeader() failed: %Rrc (on User-Agent)"), __FUNCTION__, vrc);
365
366 ProxyMode_T enmProxyMode;
367 rc = pSystemProperties->COMGETTER(ProxyMode)(&enmProxyMode);
368 if (FAILED(rc))
369 return setErrorVrc(rc, tr("%s: ISystemProperties::proxyMode() failed: %Rrc"), __FUNCTION__, rc);
370
371 if (enmProxyMode == ProxyMode_Manual)
372 {
373 Bstr strProxyURL;
374
375 rc = pSystemProperties->COMGETTER(ProxyURL)(strProxyURL.asOutParam());
376 if (FAILED(rc))
377 return setErrorVrc(rc, tr("%s: ISystemProperties::proxyURL() failed: %Rrc"), __FUNCTION__, rc);
378 vrc = RTHttpSetProxyByUrl(hHttp, Utf8Str(strProxyURL).c_str());
379 if (RT_FAILURE(vrc))
380 return setErrorVrc(vrc, tr("%s: RTHttpSetProxyByUrl() failed: %Rrc"), __FUNCTION__, vrc);
381 }
382 else if (enmProxyMode == ProxyMode_System)
383 {
384 vrc = RTHttpUseSystemProxySettings(hHttp);
385 if (RT_FAILURE(vrc))
386 return setErrorVrc(vrc, tr("%s: RTHttpUseSystemProxySettings() failed: %Rrc"), __FUNCTION__, vrc);
387 }
388
389 void *pvResponse = 0;
390 size_t cbResponse = 0;
391 vrc = RTHttpGetBinary(hHttp, Utf8Str(url).c_str(), &pvResponse, &cbResponse);
392 if (RT_FAILURE(vrc))
393 return setErrorVrc(vrc, tr("%s: RTHttpGetBinary() failed: %Rrc"), __FUNCTION__, vrc);
394
395 RTCList<RTCString> lstHttpReply = RTCString((char *)pvResponse, (size_t)cbResponse).split(" ", RTCString::RemoveEmptyParts);
396 RTHttpFreeResponse(pvResponse);
397
398 // If url is platform=DARWIN_64BITS_GENERIC&version=6.0.12&branch=stable for example, the reply is:
399 // reply[0] = 6.0.14
400 // reply[1] = https://download.virtualbox.org/virtualbox/6.0.14/VirtualBox-6.0.14-133895-OSX.dmg
401 // If no update required, 'UPTODATE' is returned.
402 if (strcmp(lstHttpReply.at(0).c_str(), "UPTODATE") == 0)
403 {
404 m_updateNeeded = FALSE;
405 }
406 else
407 {
408 m_updateNeeded = TRUE;
409 m_updateVersion = lstHttpReply.at(0).c_str();
410 m_updateURL = lstHttpReply.at(1).c_str();
411 LogRelFunc(("HTTP server reply = %s %s\n", lstHttpReply.at(0).c_str(), lstHttpReply.at(1).c_str()));
412 }
413
414 // clean-up HTTP request paperwork
415 if (hHttp != NIL_RTHTTP)
416 RTHttpDestroy(hHttp);
417
418 return S_OK;
419}
420
421/* static */
422HRESULT HostUpdate::i_updateCheckTask(UpdateCheckTask *pTask)
423{
424 LogFlowFuncEnter();
425
426 AutoCaller autoCaller(this);
427 if (FAILED(autoCaller.rc())) return autoCaller.rc();
428
429 if (pTask->m_checkType == UpdateCheckType_VirtualBox)
430 pTask->m_rc = i_checkForVBoxUpdate();
431
432#if 0
433 else if (pTask->m_checkType == UpdateCheckType_ExtensionPack)
434 ;
435 else if (pTask->m_checkType == UpdateCheckType_GuestAdditions)
436 ;
437 else
438 assert();
439#endif
440
441 if (!pTask->m_ptrProgress.isNull())
442 pTask->m_ptrProgress->i_notifyComplete(pTask->m_rc);
443
444 LogFlowFunc(("rc=%Rhrc\n", pTask->m_rc));
445 LogFlowFuncLeave();
446
447 return pTask->m_rc;
448}
449
450////////////////////////////////////////////////////////////////////////////////
451//
452// HostUpdate constructor / destructor
453//
454// ////////////////////////////////////////////////////////////////////////////////
455HostUpdate::HostUpdate()
456 : mVirtualBox(NULL)
457{
458}
459
460HostUpdate::~HostUpdate()
461{
462}
463
464
465HRESULT HostUpdate::FinalConstruct()
466{
467 return BaseFinalConstruct();
468}
469
470void HostUpdate::FinalRelease()
471{
472 uninit();
473
474 BaseFinalRelease();
475}
476
477HRESULT HostUpdate::init(VirtualBox *aVirtualBox)
478{
479 // Enclose the state transition NotReady->InInit->Ready.
480 AutoInitSpan autoInitSpan(this);
481 AssertReturn(autoInitSpan.isOk(), E_FAIL);
482
483 /* Weak reference to a VirtualBox object */
484 unconst(mVirtualBox) = aVirtualBox;
485
486 autoInitSpan.setSucceeded();
487 return S_OK;
488}
489
490void HostUpdate::uninit()
491{
492 // Enclose the state transition Ready->InUninit->NotReady.
493 AutoUninitSpan autoUninitSpan(this);
494 if (autoUninitSpan.uninitDone())
495 return;
496}
497
498HRESULT HostUpdate::getUpdate(ComPtr<IHostUpdate> &aUpdate)
499{
500 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
501 aUpdate = m_pHostUpdate;
502 return S_OK;
503}
504
505HRESULT HostUpdate::updateCheck(UpdateCheckType_T aCheckType,
506 ComPtr<IProgress> &aProgress)
507{
508 HRESULT rc;
509
510 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
511
512 // Check whether VirtualBox updates have been disabled before spawning the task thread.
513 ComPtr<ISystemProperties> pSystemProperties;
514 rc = mVirtualBox->COMGETTER(SystemProperties)(pSystemProperties.asOutParam());
515 if (FAILED(rc))
516 return setErrorVrc(rc, tr("%s: IVirtualBox::systemProperties() failed: %Rrc"), __FUNCTION__, rc);
517
518 BOOL fVBoxUpdateEnabled = true;
519 rc = pSystemProperties->COMGETTER(VBoxUpdateEnabled)(&fVBoxUpdateEnabled);
520 if (FAILED(rc))
521 return setErrorVrc(rc, tr("%s: retrieving ISystemProperties::VBoxUpdateEnabled failed: %Rrc"), __FUNCTION__, rc);
522
523 if (!fVBoxUpdateEnabled)
524 return E_NOTIMPL;
525
526 ComObjPtr<Progress> pProgress;
527 rc = pProgress.createObject();
528 if (FAILED(rc))
529 {
530 return rc;
531 }
532
533 rc = pProgress->init(mVirtualBox,
534 static_cast<IHostUpdate*>(this),
535 tr("Checking for software update..."),
536 TRUE /* aCancelable */);
537 if (FAILED(rc))
538 {
539 return rc;
540 }
541
542 /* initialize the worker task */
543 UpdateCheckTask *pTask = new UpdateCheckTask(aCheckType, this, pProgress);
544 rc = pTask->createThread();
545 pTask = NULL;
546 if (FAILED(rc))
547 {
548 return rc;
549 }
550
551 rc = pProgress.queryInterfaceTo(aProgress.asOutParam());
552
553 return rc;
554}
555
556HRESULT HostUpdate::getUpdateVersion(com::Utf8Str &aUpdateVersion)
557{
558 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
559
560 if (m_updateVersion.isNotEmpty())
561 {
562 aUpdateVersion = m_updateVersion;
563 }
564
565 return S_OK;
566}
567
568HRESULT HostUpdate::getUpdateURL(com::Utf8Str &aUpdateURL)
569{
570 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
571
572 if (m_updateURL.isNotEmpty())
573 {
574 aUpdateURL = m_updateURL;
575 }
576
577 return S_OK;
578}
579
580HRESULT HostUpdate::getUpdateResponse(BOOL *aUpdateNeeded)
581{
582 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
583
584 *aUpdateNeeded = m_updateNeeded;
585
586 return S_OK;
587}
588
589HRESULT HostUpdate::getUpdateCheckNeeded(BOOL *aUpdateCheckNeeded)
590{
591 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
592
593 HRESULT rc;
594 ComPtr<ISystemProperties> pSystemProperties;
595 rc = mVirtualBox->COMGETTER(SystemProperties)(pSystemProperties.asOutParam());
596 if (FAILED(rc))
597 return rc;
598
599 BOOL fVBoxUpdateEnabled;
600 rc = pSystemProperties->COMGETTER(VBoxUpdateEnabled)(&fVBoxUpdateEnabled);
601 if (FAILED(rc))
602 return rc;
603
604 if (!fVBoxUpdateEnabled)
605 {
606 *aUpdateCheckNeeded = false;
607 return S_OK;
608 }
609
610 Bstr strVBoxUpdateLastCheckDate;
611 rc = pSystemProperties->COMGETTER(VBoxUpdateLastCheckDate)(strVBoxUpdateLastCheckDate.asOutParam());
612 if (FAILED(rc))
613 return rc;
614
615 // No prior update check performed so do so now
616 if (strVBoxUpdateLastCheckDate.isEmpty())
617 {
618 *aUpdateCheckNeeded = true;
619 return S_OK;
620 }
621
622 // convert stored timestamp to time spec
623 RTTIMESPEC LastCheckTime;
624 if (!RTTimeSpecFromString(&LastCheckTime, Utf8Str(strVBoxUpdateLastCheckDate).c_str()))
625 {
626 *aUpdateCheckNeeded = true;
627 return S_OK;
628 }
629
630 ULONG uVBoxUpdateFrequency = 0; // value in days
631 rc = pSystemProperties->COMGETTER(VBoxUpdateFrequency)(&uVBoxUpdateFrequency);
632 if (FAILED(rc))
633 return rc;
634
635 if (!uVBoxUpdateFrequency)
636 {
637 *aUpdateCheckNeeded = false;
638 return S_OK;
639 }
640
641 ULONG ulSecondsInXDays = uVBoxUpdateFrequency /* in days */ * 24 /* hours */ * 60 /* minutes */ * 60 /* seconds */;
642 RTTIMESPEC TimeNow;
643 (void) RTTimeNow(&TimeNow);
644 PRTTIMESPEC TimeDiff = RTTimeSpecSub(&TimeNow, &LastCheckTime);
645
646 LogRelFunc(("Checking if seconds since last check (%ld) >= Number of seconds in %lu day%s (%ld)\n",
647 RTTimeSpecGetSeconds(TimeDiff), uVBoxUpdateFrequency, uVBoxUpdateFrequency > 1 ? "s" : "", ulSecondsInXDays));
648
649 if (RTTimeSpecGetSeconds(TimeDiff) >= ulSecondsInXDays)
650 *aUpdateCheckNeeded = true;
651
652 return S_OK;
653}
654
655/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette