summaryrefslogtreecommitdiffstats
path: root/src/VBox/Main
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 22:55:45 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 22:55:45 +0000
commit04aecf1372d30eb709d8de65152535ab66dcb74a (patch)
treed1e4d8c453a76465e8b63119314a28d39b474479 /src/VBox/Main
parentAdding upstream version 7.0.14-dfsg. (diff)
downloadvirtualbox-04aecf1372d30eb709d8de65152535ab66dcb74a.tar.xz
virtualbox-04aecf1372d30eb709d8de65152535ab66dcb74a.zip
Adding upstream version 7.0.16-dfsg.upstream/7.0.16-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Main')
-rw-r--r--src/VBox/Main/include/AudioSettingsImpl.h1
-rw-r--r--src/VBox/Main/src-all/win/VBoxProxyStub.c2
-rw-r--r--src/VBox/Main/src-client/GuestSessionImplTasks.cpp72
-rw-r--r--src/VBox/Main/src-global/win/VBoxSDS.cpp36
-rw-r--r--src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp2
-rw-r--r--src/VBox/Main/src-server/AudioAdapterImpl.cpp40
-rw-r--r--src/VBox/Main/src-server/AudioSettingsImpl.cpp14
-rw-r--r--src/VBox/Main/webservice/vboxweb.cpp175
-rwxr-xr-x[-rw-r--r--]src/VBox/Main/webservice/websrv-python.xsl0
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