diff options
author | Christophe Fergeau <cfergeau@redhat.com> | 2012-11-16 17:49:28 +0100 |
---|---|---|
committer | Christophe Fergeau <cfergeau@redhat.com> | 2012-11-16 17:49:28 +0100 |
commit | e8ca47be43034b4b913810f224a6777b89c27530 (patch) | |
tree | 53e47b9c56c401650b12eda24cb5f1744a10eb53 | |
parent | be0ef4f845fcc773807daa31b2f779b0d61c20f5 (diff) |
More Windows work
-rw-r--r-- | Win/controller.cpp | 147 |
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; } |