diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 22:55:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 22:55:46 +0000 |
commit | 96647a898d62d699808316238dfb933d960413f2 (patch) | |
tree | 0138491ada40b7b3fcb80d4b219fa7922ae8f512 /src/VBox/Main | |
parent | Adding debian version 7.0.14-dfsg-4. (diff) | |
download | virtualbox-96647a898d62d699808316238dfb933d960413f2.tar.xz virtualbox-96647a898d62d699808316238dfb933d960413f2.zip |
Merging upstream version 7.0.16-dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/VBox/Main/include/AudioSettingsImpl.h | 1 | ||||
-rw-r--r-- | src/VBox/Main/src-all/win/VBoxProxyStub.c | 2 | ||||
-rw-r--r-- | src/VBox/Main/src-client/GuestSessionImplTasks.cpp | 72 | ||||
-rw-r--r-- | src/VBox/Main/src-global/win/VBoxSDS.cpp | 36 | ||||
-rw-r--r-- | src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp | 2 | ||||
-rw-r--r-- | src/VBox/Main/src-server/AudioAdapterImpl.cpp | 40 | ||||
-rw-r--r-- | src/VBox/Main/src-server/AudioSettingsImpl.cpp | 14 | ||||
-rw-r--r-- | src/VBox/Main/webservice/vboxweb.cpp | 175 | ||||
-rwxr-xr-x[-rw-r--r--] | src/VBox/Main/webservice/websrv-python.xsl | 0 |
9 files changed, 163 insertions, 179 deletions
diff --git a/src/VBox/Main/include/AudioSettingsImpl.h b/src/VBox/Main/include/AudioSettingsImpl.h index e5ec0b31..d9387165 100644 --- a/src/VBox/Main/include/AudioSettingsImpl.h +++ b/src/VBox/Main/include/AudioSettingsImpl.h @@ -64,6 +64,7 @@ public: // public methods only for internal purposes bool i_canChangeSettings(void); + Machine *i_getMachine(void); void i_onAdapterChanged(IAudioAdapter *pAdapter); void i_onHostDeviceChanged(IHostAudioDevice *pDevice, bool fIsNew, AudioDeviceState_T enmState, IVirtualBoxErrorInfo *pErrInfo); void i_onSettingsChanged(void); diff --git a/src/VBox/Main/src-all/win/VBoxProxyStub.c b/src/VBox/Main/src-all/win/VBoxProxyStub.c index 87125091..63d84b9c 100644 --- a/src/VBox/Main/src-all/win/VBoxProxyStub.c +++ b/src/VBox/Main/src-all/win/VBoxProxyStub.c @@ -2491,7 +2491,7 @@ static void vbpsUpdateWindowsService(VBPSREGSTATE *pState, const WCHAR *pwszVBox NULL /* pwszLoadOrderGroup */, NULL /* pdwTagId */, wszzDependencies, - NULL /* pwszServiceStartName */, + pwszServiceStartName /* pwszServiceStartName */, NULL /* pwszPassword */); if (hService != NULL) { diff --git a/src/VBox/Main/src-client/GuestSessionImplTasks.cpp b/src/VBox/Main/src-client/GuestSessionImplTasks.cpp index 59fbf06c..9a74e050 100644 --- a/src/VBox/Main/src-client/GuestSessionImplTasks.cpp +++ b/src/VBox/Main/src-client/GuestSessionImplTasks.cpp @@ -2969,77 +2969,41 @@ int GuestSessionTaskUpdateAdditions::Run(void) } else { + if (RT_SUCCESS(vrc)) + vrc = setProgress(5); + Utf8Str strUpdateDir; - vrc = setProgress(5); + /* + * Prepare the update directory. + */ if (RT_SUCCESS(vrc)) { - /* Try getting the installed Guest Additions version to know whether we - * can install our temporary Guest Addition data into the original installation - * directory. - * - * Because versions prior to 4.2 had bugs wrt spaces in paths we have to choose - * a different location then. - */ - bool fUseInstallDir = false; - - Utf8Str strAddsVer; - vrc = getGuestProperty(pGuest, "/VirtualBox/GuestAdd/Version", strAddsVer); - if ( RT_SUCCESS(vrc) - && RTStrVersionCompare(strAddsVer.c_str(), "4.2r80329") > 0) - { - fUseInstallDir = true; - } - - if (fUseInstallDir) - { - vrc = getGuestProperty(pGuest, "/VirtualBox/GuestAdd/InstallDir", strUpdateDir); - if (RT_SUCCESS(vrc)) - { - if (strUpdateDir.isNotEmpty()) - { - if (osType == eOSType_Windows) - { - strUpdateDir.findReplace('/', '\\'); - strUpdateDir.append("\\Update\\"); - } - else - strUpdateDir.append("/update/"); - } - /* else Older Guest Additions might not handle this property correctly. */ - } - /* Ditto. */ - } - - /** @todo Set fallback installation directory. Make this a *lot* smarter. Later. */ - if (strUpdateDir.isEmpty()) + /* Note: No fallback to unsafe guest locations! See @bugref{10625}. */ + int vrcGuest; + vrc = pSession->i_fsCreateTemp("VBoxAutoUpdate-XXXXXXXXXXXX", "" /* Use default temp dir */, + true /* fDirectory */, strUpdateDir, 755 /* Mode */, false /* fSecure */, &vrcGuest); + if (RT_SUCCESS(vrc)) { if (osType == eOSType_Windows) - strUpdateDir = "C:\\Temp\\"; + strUpdateDir.append("\\"); else - strUpdateDir = "/tmp/"; - } - } - - /* Create the installation directory. */ - int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS; - if (RT_SUCCESS(vrc)) - { - LogRel(("Guest Additions update directory is: %s\n", strUpdateDir.c_str())); + strUpdateDir.append("/"); - vrc = pSession->i_directoryCreate(strUpdateDir, 755 /* Mode */, DirectoryCreateFlag_Parents, &vrcGuest); - if (RT_FAILURE(vrc)) + LogRel(("Guest Additions update directory is: %s\n", strUpdateDir.c_str())); + } + else { switch (vrc) { case VERR_GSTCTL_GUEST_ERROR: - hrc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, tr("Creating installation directory on guest failed"), + hrc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, tr("Creating update directory on guest failed"), GuestErrorInfo(GuestErrorInfo::Type_Directory, vrcGuest, strUpdateDir.c_str())); break; default: hrc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, - Utf8StrFmt(tr("Creating installation directory \"%s\" on guest failed: %Rrc"), + Utf8StrFmt(tr("Creating update directory \"%s\" on guest failed: %Rrc"), strUpdateDir.c_str(), vrc)); break; } diff --git a/src/VBox/Main/src-global/win/VBoxSDS.cpp b/src/VBox/Main/src-global/win/VBoxSDS.cpp index 6bc7506f..e89bfd7a 100644 --- a/src/VBox/Main/src-global/win/VBoxSDS.cpp +++ b/src/VBox/Main/src-global/win/VBoxSDS.cpp @@ -104,6 +104,7 @@ #include <iprt/buildconfig.h> #include <iprt/dir.h> #include <iprt/env.h> +#include <iprt/err.h> #include <iprt/getopt.h> #include <iprt/initterm.h> #include <iprt/path.h> @@ -911,10 +912,14 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine } /* - * Default log location is %ProgramData%\VirtualBox\VBoxSDS.log, falling back - * on %_CWD%\VBoxSDS.log (where _CWD typicaly is 'C:\Windows\System32'). + * Default log location (LOGDIR) is %APPDATA%\VirtualBox\VBoxSDS.log. * - * We change the current directory to %ProgramData%\VirtualBox\ if possible. + * When running VBoxSDS as a regular user, LOGDIR typically will be 'C:\Users\<User>\AppData\Roaming\VirtualBox\'. + * When running VBoxSDS as a service (via SCM), LOGDIR typically will be 'C:\Windows\System32\config\systemprofile\AppData\Roaming\VirtualBox\'. + * + * We change the current directory to LOGDIR if possible. + * + * See @bugref{10632}. * * We only create the log file when running VBoxSDS normally, but not * when registering/unregistering, at least for now. @@ -924,14 +929,19 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine char szLogFile[RTPATH_MAX]; if (!pszLogFile || !*pszLogFile) { - WCHAR wszAppData[MAX_PATH + 16]; - if (SHGetSpecialFolderPathW(NULL, wszAppData, CSIDL_COMMON_APPDATA, TRUE /*fCreate*/)) + WCHAR wszSpecialFolder[MAX_PATH + 16]; + if (SHGetSpecialFolderPathW(NULL, wszSpecialFolder, CSIDL_APPDATA, TRUE /*fCreate*/)) { char *pszConv = szLogFile; - vrc = RTUtf16ToUtf8Ex(wszAppData, RTSTR_MAX, &pszConv, sizeof(szLogFile) - 12, NULL); + vrc = RTUtf16ToUtf8Ex(wszSpecialFolder, RTSTR_MAX, &pszConv, sizeof(szLogFile) - 12, NULL); } - else - vrc = RTEnvGetUtf8("ProgramData", szLogFile, sizeof(szLogFile) - sizeof("VBoxSDS.log"), NULL); + else if (SHGetSpecialFolderPathW(NULL, wszSpecialFolder, CSIDL_SYSTEM, TRUE /*fCreate*/)) + { + char *pszConv = szLogFile; + vrc = RTUtf16ToUtf8Ex(wszSpecialFolder, RTSTR_MAX, &pszConv, sizeof(szLogFile) - 12, NULL); + } + else /* Note! No fallback to environment variables or such. See @bugref{10632}. */ + vrc = VERR_PATH_NOT_FOUND; if (RT_SUCCESS(vrc)) { vrc = RTPathAppend(szLogFile, sizeof(szLogFile), "VirtualBox\\"); @@ -942,14 +952,14 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine vrc = RTDirCreate(szLogFile, 0755, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_DONT_SET); if (RT_SUCCESS(vrc)) { - /* Change into it. */ - RTPathSetCurrent(szLogFile); + /* Change into it. + * If this fails, better don't continue, as there might be something fishy. */ + vrc = RTPathSetCurrent(szLogFile); + if (RT_SUCCESS(vrc)) + vrc = RTStrCat(szLogFile, sizeof(szLogFile), "VBoxSDS.log"); } } } - if (RT_FAILURE(vrc)) /* ignore any failure above */ - szLogFile[0] = '\0'; - vrc = RTStrCat(szLogFile, sizeof(szLogFile), "VBoxSDS.log"); if (RT_FAILURE(vrc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to construct release log filename: %Rrc", vrc); pszLogFile = szLogFile; diff --git a/src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp b/src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp index 1b98c629..1db8fa61 100644 --- a/src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp +++ b/src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp @@ -609,7 +609,7 @@ STDMETHODIMP VirtualBoxSDS::LaunchVMProcess(IN_BSTR aMachine, IN_BSTR aComment, else { hrc = VBOX_E_IPRT_ERROR; - LogRel(("VirtualBoxSDS::LaunchVMProcess: launchVM failed: %Rhrc (%Rrc)\n", hrc)); + LogRel(("VirtualBoxSDS::LaunchVMProcess: launchVM failed: %Rhrc (%Rrc)\n", hrc, vrc)); } } catch (...) diff --git a/src/VBox/Main/src-server/AudioAdapterImpl.cpp b/src/VBox/Main/src-server/AudioAdapterImpl.cpp index 66e40c6e..5c388771 100644 --- a/src/VBox/Main/src-server/AudioAdapterImpl.cpp +++ b/src/VBox/Main/src-server/AudioAdapterImpl.cpp @@ -233,6 +233,10 @@ HRESULT AudioAdapter::setEnabled(BOOL aEnabled) AutoCaller autoCaller(this); if (FAILED(autoCaller.hrc())) return autoCaller.hrc(); + /* the machine needs to be mutable */ + AutoMutableStateDependency adep(m->pParent->i_getMachine()); + if (FAILED(adep.hrc())) return adep.hrc(); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (m->bd->fEnabled != RT_BOOL(aEnabled)) @@ -241,7 +245,7 @@ HRESULT AudioAdapter::setEnabled(BOOL aEnabled) m->bd->fEnabled = RT_BOOL(aEnabled); alock.release(); - m->pParent->i_onSettingsChanged(); // mParent is const, needs no locking + m->pParent->i_onSettingsChanged(); // m->pParent is const, needs no locking m->pParent->i_onAdapterChanged(this); } @@ -265,6 +269,10 @@ HRESULT AudioAdapter::setEnabledIn(BOOL aEnabled) AutoCaller autoCaller(this); if (FAILED(autoCaller.hrc())) return autoCaller.hrc(); + /* the machine needs to be mutable */ + AutoMutableOrSavedOrRunningStateDependency adep(m->pParent->i_getMachine()); + if (FAILED(adep.hrc())) return adep.hrc(); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (RT_BOOL(aEnabled) != m->bd->fEnabledIn) @@ -274,7 +282,7 @@ HRESULT AudioAdapter::setEnabledIn(BOOL aEnabled) alock.release(); - m->pParent->i_onSettingsChanged(); // mParent is const, needs no locking + m->pParent->i_onSettingsChanged(); // m->pParent is const, needs no locking m->pParent->i_onAdapterChanged(this); } @@ -298,6 +306,10 @@ HRESULT AudioAdapter::setEnabledOut(BOOL aEnabled) AutoCaller autoCaller(this); if (FAILED(autoCaller.hrc())) return autoCaller.hrc(); + /* the machine needs to be mutable */ + AutoMutableOrSavedOrRunningStateDependency adep(m->pParent->i_getMachine()); + if (FAILED(adep.hrc())) return adep.hrc(); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (RT_BOOL(aEnabled) != m->bd->fEnabledOut) @@ -307,7 +319,7 @@ HRESULT AudioAdapter::setEnabledOut(BOOL aEnabled) alock.release(); - m->pParent->i_onSettingsChanged(); // mParent is const, needs no locking + m->pParent->i_onSettingsChanged(); // m->pParent is const, needs no locking m->pParent->i_onAdapterChanged(this); } @@ -331,6 +343,10 @@ HRESULT AudioAdapter::setAudioDriver(AudioDriverType_T aAudioDriver) AutoCaller autoCaller(this); if (FAILED(autoCaller.hrc())) return autoCaller.hrc(); + /* the machine needs to be mutable */ + AutoMutableOrSavedStateDependency adep(m->pParent->i_getMachine()); + if (FAILED(adep.hrc())) return adep.hrc(); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); HRESULT hrc = S_OK; @@ -344,7 +360,7 @@ HRESULT AudioAdapter::setAudioDriver(AudioDriverType_T aAudioDriver) alock.release(); - m->pParent->i_onSettingsChanged(); // mParent is const, needs no locking + m->pParent->i_onSettingsChanged(); // m->pParent is const, needs no locking } else { @@ -373,6 +389,10 @@ HRESULT AudioAdapter::setAudioController(AudioControllerType_T aAudioController) AutoCaller autoCaller(this); if (FAILED(autoCaller.hrc())) return autoCaller.hrc(); + /* the machine needs to be mutable */ + AutoMutableStateDependency adep(m->pParent->i_getMachine()); + if (FAILED(adep.hrc())) return adep.hrc(); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); HRESULT hrc = S_OK; @@ -411,7 +431,7 @@ HRESULT AudioAdapter::setAudioController(AudioControllerType_T aAudioController) alock.release(); - m->pParent->i_onSettingsChanged(); // mParent is const, needs no locking + m->pParent->i_onSettingsChanged(); // m->pParent is const, needs no locking } } @@ -435,6 +455,10 @@ HRESULT AudioAdapter::setAudioCodec(AudioCodecType_T aAudioCodec) AutoCaller autoCaller(this); if (FAILED(autoCaller.hrc())) return autoCaller.hrc(); + /* the machine needs to be mutable */ + AutoMutableStateDependency adep(m->pParent->i_getMachine()); + if (FAILED(adep.hrc())) return adep.hrc(); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); HRESULT hrc = S_OK; @@ -484,7 +508,7 @@ HRESULT AudioAdapter::setAudioCodec(AudioCodecType_T aAudioCodec) alock.release(); - m->pParent->i_onSettingsChanged(); // mParent is const, needs no locking + m->pParent->i_onSettingsChanged(); // m->pParent is const, needs no locking } return hrc; @@ -530,6 +554,10 @@ HRESULT AudioAdapter::setProperty(const com::Utf8Str &aKey, const com::Utf8Str & AutoCaller autoCaller(this); if (FAILED(autoCaller.hrc())) return autoCaller.hrc(); + /* the machine needs to be mutable */ + AutoMutableStateDependency adep(m->pParent->i_getMachine()); + if (FAILED(adep.hrc())) return adep.hrc(); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); /* Generic properties processing. diff --git a/src/VBox/Main/src-server/AudioSettingsImpl.cpp b/src/VBox/Main/src-server/AudioSettingsImpl.cpp index b7736f1f..851fea77 100644 --- a/src/VBox/Main/src-server/AudioSettingsImpl.cpp +++ b/src/VBox/Main/src-server/AudioSettingsImpl.cpp @@ -247,6 +247,16 @@ bool AudioSettings::i_canChangeSettings(void) } /** + * Returns a (weak) pointer of the audio setting's machine object. + * + * @returns Wweak pointer of the audio setting's machine object. + */ +Machine *AudioSettings::i_getMachine(void) +{ + return m->pMachine; // m->pMachine is const, needs no locking +} + +/** * Gets called when the machine object needs to know that audio adapter settings * have been changed. * @@ -255,7 +265,7 @@ bool AudioSettings::i_canChangeSettings(void) void AudioSettings::i_onAdapterChanged(IAudioAdapter *pAdapter) { AssertPtrReturnVoid(pAdapter); - m->pMachine->i_onAudioAdapterChange(pAdapter); // mParent is const, needs no locking + m->pMachine->i_onAudioAdapterChange(pAdapter); // m->pMachine is const, needs no locking } /** @@ -271,7 +281,7 @@ void AudioSettings::i_onHostDeviceChanged(IHostAudioDevice *pDevice, bool fIsNew, AudioDeviceState_T enmState, IVirtualBoxErrorInfo *pErrInfo) { AssertPtrReturnVoid(pDevice); - m->pMachine->i_onHostAudioDeviceChange(pDevice, fIsNew, enmState, pErrInfo); // mParent is const, needs no locking + m->pMachine->i_onHostAudioDeviceChange(pDevice, fIsNew, enmState, pErrInfo); // m->pMachine is const, needs no locking } /** diff --git a/src/VBox/Main/webservice/vboxweb.cpp b/src/VBox/Main/webservice/vboxweb.cpp index eb1c44a0..e3052600 100644 --- a/src/VBox/Main/webservice/vboxweb.cpp +++ b/src/VBox/Main/webservice/vboxweb.cpp @@ -139,7 +139,7 @@ static int g_iWatchdogCheckInterval = 5; static const char *g_pcszBindToHost = NULL; // host; NULL = localhost static unsigned int g_uBindToPort = 18083; // port -static unsigned int g_uBacklog = 100; // backlog = max queue size for requests +static unsigned int g_uBacklog = 100; // backlog = max queue size for connections #ifdef WITH_OPENSSL static bool g_fSSL = false; // if SSL is enabled @@ -306,7 +306,7 @@ static void DisplayHelp() break; case 'k': - pcszDescr = "Maximum number of requests before a socket will be closed (100)."; + pcszDescr = "Maximum number of requests before a connection will be closed (100)."; break; case 'A': @@ -361,30 +361,13 @@ public: * Constructor. Creates the new thread and makes it call process() for processing the queue. * @param u Thread number. (So we can count from 1 and be readable.) * @param q SoapQ instance which has the queue to process. - * @param soap struct soap instance from main() which we copy here. */ SoapThread(size_t u, - SoapQ &q, - const struct soap *soap) + SoapQ &q) : m_u(u), - m_strThread(com::Utf8StrFmt("SQW%02d", m_u)), m_pQ(&q) { - // make a copy of the soap struct for the new thread - m_soap = soap_copy(soap); - m_soap->fget = fnHttpGet; - - /* The soap.max_keep_alive value can be set to the maximum keep-alive calls allowed, - * which is important to avoid a client from holding a thread indefinitely. - * http://www.cs.fsu.edu/~engelen/soapdoc2.html#sec:keepalive - * - * Strings with 8-bit content can hold ASCII (default) or UTF8. The latter is - * possible by enabling the SOAP_C_UTFSTRING flag. - */ - soap_set_omode(m_soap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING); - soap_set_imode(m_soap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING); - m_soap->max_keep_alive = g_cMaxKeepAlive; - + m_strThread = com::Utf8StrFmt("SQW%02d", m_u); int vrc = RTThreadCreate(&m_pThread, fntWrapper, this, // pvUser @@ -431,7 +414,6 @@ public: size_t m_u; // thread number com::Utf8Str m_strThread; // thread name ("SoapQWrkXX") SoapQ *m_pQ; // the single SOAP queue that all the threads service - struct soap *m_soap; // copy of the soap structure for this thread (from soap_copy()) RTTHREAD m_pThread; // IPRT thread struct for this thread }; @@ -446,11 +428,9 @@ public: /** * Constructor. Creates the soap queue. - * @param pSoap */ - SoapQ(const struct soap *pSoap) - : m_soap(pSoap), - m_mutex(util::LOCKCLASS_OBJECTSTATE), // lowest lock order, no other may be held while this is held + SoapQ() + : m_mutex(util::LOCKCLASS_OBJECTSTATE), // lowest lock order, no other may be held while this is held m_cIdleThreads(0) { RTSemEventMultiCreate(&m_event); @@ -474,16 +454,29 @@ public: } RTSemEventMultiDestroy(m_event); + + while (!m_llSocketsQ.empty()) + { + struct soap *pSoap = m_llSocketsQ.front(); + m_llSocketsQ.pop_front(); + + if (pSoap == NULL || !soap_valid_socket(pSoap->socket)) + continue; + + soap_destroy(pSoap); // clean up class instances + soap_end(pSoap); // clean up everything and close socket + soap_free(pSoap); // free soap connection + } } /** - * Adds the given socket to the SOAP queue and posts the + * Adds the given soap connection to the SOAP queue and posts the * member event sem to wake up the workers. Called on the main thread - * whenever a socket has work to do. Creates a new SOAP thread on the + * whenever a connection comes in. Creates a new SOAP thread on the * first call or when all existing threads are busy. - * @param s Socket from soap_accept() which has work to do. + * @param pSoap connection */ - size_t add(SOAP_SOCKET s) + size_t add(const struct soap *pSoap) { size_t cItems; util::AutoWriteLock qlock(m_mutex COMMA_LOCKVAL_SRC_POS); @@ -496,17 +489,16 @@ public: ) { SoapThread *pst = new SoapThread(m_llAllThreads.size() + 1, - *this, - m_soap); + *this); m_llAllThreads.push_back(pst); util::AutoWriteLock thrLock(g_pThreadsLockHandle COMMA_LOCKVAL_SRC_POS); g_mapThreads[pst->m_pThread] = com::Utf8StrFmt("[%3u]", pst->m_u); ++m_cIdleThreads; } - // enqueue the socket of this connection and post eventsem so that - // one of the threads (possibly the one just created) can pick it up - m_llSocketsQ.push_back(s); + // enqueue this connection and post eventsem so that one of the threads + // (possibly the one just created) can pick it up + m_llSocketsQ.push_back(soap_copy(pSoap)); cItems = m_llSocketsQ.size(); qlock.release(); @@ -518,14 +510,14 @@ public: /** * Blocks the current thread until work comes in; then returns - * the SOAP socket which has work to do. This reduces m_cIdleThreads + * the SOAP connection which has work to do. This reduces m_cIdleThreads * by one, and the caller MUST call done() when it's done processing. * Called from the worker threads. * @param cIdleThreads out: no. of threads which are currently idle (not counting the caller) * @param cThreads out: total no. of SOAP threads running * @return */ - SOAP_SOCKET get(size_t &cIdleThreads, size_t &cThreads) + struct soap *get(size_t &cIdleThreads, size_t &cThreads) { while (g_fKeepRunning) { @@ -538,7 +530,7 @@ public: util::AutoWriteLock qlock(m_mutex COMMA_LOCKVAL_SRC_POS); if (!m_llSocketsQ.empty()) { - SOAP_SOCKET socket = m_llSocketsQ.front(); + struct soap *pSoap = m_llSocketsQ.front(); m_llSocketsQ.pop_front(); cIdleThreads = --m_cIdleThreads; cThreads = m_llAllThreads.size(); @@ -551,12 +543,12 @@ public: qlock.release(); - return socket; + return pSoap; } // nothing to do: keep looping } - return SOAP_INVALID_SOCKET; + return NULL; } /** @@ -571,7 +563,7 @@ public: /** * To be called by a worker thread when signing off, i.e. no longer - * willing to process requests. + * willing to process SOAP connections. */ void signoff(SoapThread *th) { @@ -587,8 +579,6 @@ public: } } - const struct soap *m_soap; // soap structure created by main(), passed to constructor - util::WriteLockHandle m_mutex; RTSEMEVENTMULTI m_event; // posted by add(), blocked on by get() @@ -596,15 +586,15 @@ public: size_t m_cIdleThreads; // threads which are currently idle (statistics) // A std::list abused as a queue; this contains the actual jobs to do, - // each int being a socket from soap_accept() - std::list<SOAP_SOCKET> m_llSocketsQ; + // each entry being a connection from soap_accept() passed through SoapQ::add. + std::list<struct soap *> m_llSocketsQ; }; /** * Thread function for each of the SOAP queue worker threads. This keeps * running, blocks on the event semaphore in SoapThread.SoapQ and picks - * up a socket from the queue therein, which has been put there by - * beginProcessing(). + * up a connection from the queue therein, which has been put there by + * SoapQ::add(). */ void SoapThread::process() { @@ -612,39 +602,54 @@ void SoapThread::process() while (g_fKeepRunning) { - // wait for a socket to arrive on the queue + // wait for a job to arrive on the queue size_t cIdleThreads = 0, cThreads = 0; - m_soap->socket = m_pQ->get(cIdleThreads, cThreads); + struct soap *pSoap = m_pQ->get(cIdleThreads, cThreads); - if (!soap_valid_socket(m_soap->socket)) + if (pSoap == NULL || !soap_valid_socket(pSoap->socket)) continue; + pSoap->fget = fnHttpGet; + + /* The soap.max_keep_alive value can be set to the maximum keep-alive calls allowed, + * which is important to avoid a client from holding a thread indefinitely. + * http://www.cs.fsu.edu/~engelen/soapdoc2.html#sec:keepalive + * + * Strings with 8-bit content can hold ASCII (default) or UTF8. The latter is + * possible by enabling the SOAP_C_UTFSTRING flag. + */ + soap_set_omode(pSoap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING); + soap_set_imode(pSoap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING); + pSoap->max_keep_alive = g_cMaxKeepAlive; + LogRel(("Processing connection from IP=%RTnaipv4 socket=%d (%d out of %d threads idle)\n", - RT_H2N_U32(m_soap->ip), m_soap->socket, cIdleThreads, cThreads)); + RT_H2N_U32(pSoap->ip), pSoap->socket, cIdleThreads, cThreads)); // Ensure that we don't get stuck indefinitely for connections using // keepalive, otherwise stale connections tie up worker threads. - m_soap->send_timeout = 60; - m_soap->recv_timeout = 60; + pSoap->send_timeout = 60; + pSoap->recv_timeout = 60; // Limit the maximum SOAP request size to a generous amount, just to // be on the safe side (SOAP is quite wordy when representing arrays, // and some API uses need to deal with large arrays). Good that binary // data is no longer represented by byte arrays... - m_soap->recv_maxlength = _16M; + pSoap->recv_maxlength = _16M; // process the request; this goes into the COM code in methodmaps.cpp + do { #ifdef WITH_OPENSSL - if (g_fSSL && soap_ssl_accept(m_soap)) + if (g_fSSL && soap_ssl_accept(pSoap)) { - WebLogSoapError(m_soap); + WebLogSoapError(pSoap); break; } #endif /* WITH_OPENSSL */ - soap_serve(m_soap); + soap_serve(pSoap); } while (0); - soap_destroy(m_soap); // clean up class instances - soap_end(m_soap); // clean up everything and close socket + soap_destroy(pSoap); // clean up class instances + soap_end(pSoap); // clean up everything and close connection + soap_free(pSoap); // free soap connection // tell the queue we're idle again m_pQ->done(); @@ -908,6 +913,7 @@ static void doQueuesLoop() } #endif /* WITH_OPENSSL */ + soap.accept_timeout = 60; soap.bind_flags |= SO_REUSEADDR; // avoid EADDRINUSE on bind() @@ -915,7 +921,7 @@ static void doQueuesLoop() m = soap_bind(&soap, g_pcszBindToHost ? g_pcszBindToHost : "localhost", // safe default host g_uBindToPort, // port - g_uBacklog); // backlog = max queue size for requests + g_uBacklog); // backlog = max queue size for connections if (m == SOAP_INVALID_SOCKET) WebLogSoapError(&soap); else @@ -930,65 +936,30 @@ static void doQueuesLoop() g_uBindToPort, pszSsl, m)); // initialize thread queue, mutex and eventsem - g_pSoapQ = new SoapQ(&soap); + g_pSoapQ = new SoapQ(); uint64_t cAccepted = 1; while (g_fKeepRunning) { - struct timeval timeout; - fd_set ReadFds, WriteFds, XcptFds; - int rv; - for (;;) - { - timeout.tv_sec = 60; - timeout.tv_usec = 0; - FD_ZERO(&ReadFds); - FD_SET(soap.master, &ReadFds); - FD_ZERO(&WriteFds); - FD_SET(soap.master, &WriteFds); - FD_ZERO(&XcptFds); - FD_SET(soap.master, &XcptFds); - rv = select((int)soap.master + 1, &ReadFds, &WriteFds, &XcptFds, &timeout); - if (rv > 0) - break; // work is waiting - if (rv == 0) - continue; // timeout, not necessary to bother gsoap - // r < 0, errno -#if GSOAP_VERSION >= 208103 - if (soap_socket_errno == SOAP_EINTR) -#else - if (soap_socket_errno(soap.master) == SOAP_EINTR) -#endif - rv = 0; // re-check if we should terminate - break; - } - if (rv == 0) - continue; - - // call gSOAP to handle incoming SOAP connection - soap.accept_timeout = -1; // 1usec timeout, actual waiting is above s = soap_accept(&soap); if (!soap_valid_socket(s)) { - if (soap.errnum) + if (soap.errnum != SOAP_EINTR) WebLogSoapError(&soap); continue; } - // add the socket to the queue and tell worker threads to + // add the connection to the queue and tell worker threads to // pick up the job - size_t cItemsOnQ = g_pSoapQ->add(s); - LogRel(("Request %llu on socket %d queued for processing (%d items on Q)\n", cAccepted, s, cItemsOnQ)); + size_t cItemsOnQ = g_pSoapQ->add(&soap); + LogRel(("Connection %llu on socket %d queued for processing (%d items on Q)\n", cAccepted, s, cItemsOnQ)); cAccepted++; } delete g_pSoapQ; g_pSoapQ = NULL; - LogRel(("ending SOAP request handling\n")); - - delete g_pSoapQ; - g_pSoapQ = NULL; + LogRel(("Ending SOAP connection handling\n")); } soap_done(&soap); // close master socket and detach environment @@ -1001,7 +972,7 @@ static void doQueuesLoop() /** * Thread function for the "queue pumper" thread started from main(). This implements - * the loop that takes SOAP calls from HTTP and serves them by handing sockets to the + * the loop that takes SOAP calls from HTTP and serves them by handing connections to the * SOAP queue worker threads. */ static DECLCALLBACK(int) fntQPumper(RTTHREAD hThreadSelf, void *pvUser) diff --git a/src/VBox/Main/webservice/websrv-python.xsl b/src/VBox/Main/webservice/websrv-python.xsl index c49677b5..c49677b5 100644..100755 --- a/src/VBox/Main/webservice/websrv-python.xsl +++ b/src/VBox/Main/webservice/websrv-python.xsl |