summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Fergeau <cfergeau@redhat.com>2012-11-16 17:49:28 +0100
committerChristophe Fergeau <cfergeau@redhat.com>2012-11-16 17:49:28 +0100
commite8ca47be43034b4b913810f224a6777b89c27530 (patch)
tree53e47b9c56c401650b12eda24cb5f1744a10eb53
parentbe0ef4f845fcc773807daa31b2f779b0d61c20f5 (diff)
More Windows work
-rw-r--r--Win/controller.cpp147
1 files changed, 146 insertions, 1 deletions
diff --git a/Win/controller.cpp b/Win/controller.cpp
index 05028bb..8d240f5 100644
--- a/Win/controller.cpp
+++ b/Win/controller.cpp
@@ -56,6 +56,19 @@ SpiceController::~SpiceController()
int SpiceController::Connect()
{
+ if (m_hClientProcess) {
+ TerminateProcess(m_hClientProcess, 0);
+ CloseHandle(m_hClientProcess);
+ m_hClientProcess = NULL;
+ }
+ if (m_hClientPipe) {
+ CloseHandle(m_hClientPipe);
+ m_hClientPipe = NULL;
+ }
+ if (m_hEventThread) {
+ CloseHandle(m_hEventThread);
+ m_hEventThread = NULL;
+ }
return -1;
}
@@ -64,13 +77,61 @@ int SpiceController::Connect(const int nRetries)
return -1;
}
+void SpiceController::Cleanup()
+{
+ if (m_hClientProcess) {
+ TerminateProcess(m_hClientProcess, 0);
+ CloseHandle(m_hClientProcess);
+ m_hClientProcess = NULL;
+ }
+ if (m_hClientPipe) {
+ CloseHandle(m_hClientPipe);
+ m_hClientPipe = NULL;
+ }
+ if (m_hEventThread) {
+ CloseHandle(m_hEventThread);
+ m_hEventThread = NULL;
+ }
+}
+
void SpiceController::Disconnect()
{
+ if (m_hClientProcess == NULL) {
+ return SPICEX_ERROR_CLIENT_PROCESS_NOT_CONNECTED;
+ }
+
+ this->Cleanup();
}
uint32_t SpiceController::Write(const void *lpBuffer, uint32_t nBytesToWrite)
{
- return 0;
+ bool res = true;
+ DWORD written;
+ size_t size;
+
+ EnterCriticalSection(&m_WriteLock);
+ if (!GetOverlappedResult(m_hClientPipe, &m_OverlappedWrite, &written, FALSE)) {
+ LeaveCriticalSection(&m_WriteLock);
+ return false;
+ }
+
+ m_WritePending = false;
+ m_WriteStart = m_WriteBuffer + (m_WriteStart - m_WriteBuffer + written) % PIPE_BUF_SIZE;
+ if (m_WriteStart <= m_WriteEnd) {
+ size = m_WriteEnd - m_WriteStart;
+ } else {
+ size = m_WriteBuffer + PIPE_BUF_SIZE - m_WriteStart;
+ }
+ if (size) {
+ if (WriteFile(m_hClientPipe, m_WriteStart, (DWORD)size, NULL, &m_OverlappedWrite) ||
+ GetLastError() == ERROR_IO_PENDING) {
+ m_WritePending = true;
+ } else {
+ res = false;
+ }
+ }
+ LeaveCriticalSection(&m_WriteLock);
+ return res;
}
int SpiceController::TranslateRC(int nRC)
@@ -121,6 +182,90 @@ void SpiceController::StopClient()
bool SpiceController::StartClient(void)
{
+ if (m_hClientProcess != NULL) {
+ return SPICEX_ERROR_CLIENT_PROCESS_ALREADY_CONNECTED;
+ }
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ ZeroMemory(&m_pi, sizeof(m_pi));
+
+ // FIXME: do we need the GetModuleXXX calls?
+ // we assume the Spice client binary is located in the same dir as the
+ // ActiveX dll
+ if (hModule = GetModuleHandle(SPICE_X_DLL)) {
+ if (dwRetVal = GetModuleFileName(hModule, lpCommandLine, MAX_PATH)) {
+ // locate the 1st char of the ActiveX name (past the last '\')
+ lpProcName = (wcsrchr(lpCommandLine, L'\\') + 1);
+ // zero it so we can append the red client name
+ if (lpProcName) {
+ lpProcName[0] = 0;
+ }
+ }
+ }
+
+ lret = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\spice-space.org\\spicex", 0, KEY_READ, &hkey);
+ if (lret == ERROR_SUCCESS) {
+ DWORD dwType = REG_SZ;
+ DWORD dwSize = sizeof(lpCommandLine);
+ lret = RegQueryValueEx(hkey, L"client", NULL, &dwType, (LPBYTE)lpCommandLine, &dwSize);
+ RegCloseKey(hkey);
+ }
+
+ if (lret != ERROR_SUCCESS) {
+ StringCchPrintf(lpCommandLine, CMDLINE_LENGTH, L"%s%s --controller",
+ lpCommandLine, RED_CLIENT_FILE_NAME);
+ }
+
+ DBG(0, "Running spicec (%S)", lpCommandLine);
+
+ if (!CreateProcess(NULL, lpCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &m_pi)) {
+ DWORD err = GetLastError();
+ LOG_ERROR("Failed to run spicec (%S) -- %lu", lpCommandLine, err);
+ return MAKE_HRESULT(1, FACILITY_CREATE_RED_PROCESS, err);
+ }
+ LOG_INFO("spicec pid %lu", ::GetProcessId(m_pi.hProcess));
+ m_hClientProcess = m_pi.hProcess;
+ WaitForInputIdle(m_hClientProcess, INFINITE);
+
+ DBG(0, "connecting to spice client's pipe");
+ wchar_t lpszClientPipeName[RED_CLIENT_PIPE_NAME_MAX_LEN];
+ StringCchPrintf(lpszClientPipeName, RED_CLIENT_PIPE_NAME_MAX_LEN, RED_CLIENT_PIPE_NAME,
+ m_pi.dwProcessId);
+ for (int retry = 0; retry < 5; retry++) {
+ m_hClientPipe = CreateFile(lpszClientPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS |
+ FILE_FLAG_OVERLAPPED, NULL);
+ if (m_hClientPipe != INVALID_HANDLE_VALUE) {
+ break;
+ }
+ Sleep(1000);
+ }
+
+ // Verify the named-pipe-server owner is the current user.
+ // Do it here so upon failure use next condition cleanup code.
+ if (m_hClientPipe != INVALID_HANDLE_VALUE) {
+ if (!is_same_user(m_hClientPipe)) {
+ LOG_ERROR("Closing pipe to spicec -- it is not safe");
+ CloseHandle(m_hClientPipe);
+ m_hClientPipe = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ if (m_hClientPipe == INVALID_HANDLE_VALUE) {
+ LOG_ERROR("failed to connect to spice client pipe");
+ TerminateProcess(m_hClientProcess, 0);
+ CloseHandle(m_hClientProcess);
+ m_hClientProcess = NULL;
+ return MAKE_HRESULT(1, FACILITY_CREATE_RED_PIPE, GetLastError());
+ }
+
+ m_hEventThread = CreateThread(NULL, 0, event_thread, this, 0, NULL);
+ if (m_hEventThread == NULL) {
+ LOG_ERROR("failed to create event thread");
+ cleanup();
+ return MAKE_HRESULT(1, FACILITY_CREATE_RED_PIPE, GetLastError());
+ }
+
return false;
}