/** @file * * Definition of SVC Helper Process control routines. */ /* * Copyright (C) 2006-2007 innotek GmbH * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #include "svchlp.h" #include "HostImpl.h" #include "Logging.h" #include using namespace com; enum { PipeBufSize = 1024 }; //////////////////////////////////////////////////////////////////////////////// /** * GetLastError() is known to return NO_ERROR even after the Win32 API * function (i.e. Write() to a non-connected server end of a pipe) returns * FALSE... This method ensures that at least VERR_GENERAL_FAILURE is returned * in cases like that. Intended to be called immediately after a failed API * call. */ static inline int rtErrConvertFromWin32OnFailure() { DWORD err = GetLastError(); return err == NO_ERROR ? VERR_GENERAL_FAILURE : RTErrConvertFromWin32 (err); } //////////////////////////////////////////////////////////////////////////////// SVCHlpClient::SVCHlpClient() : mIsOpen (false), mIsServer (false) , mReadEnd (NULL), mWriteEnd (NULL) { } SVCHlpClient::~SVCHlpClient() { close(); } int SVCHlpClient::create (const char *aName) { AssertReturn (aName, VERR_INVALID_PARAMETER); if (mIsOpen) return VERR_WRONG_ORDER; Bstr pipeName = Utf8StrFmt ("\\\\.\\pipe\\%s", aName); HANDLE pipe = CreateNamedPipe (pipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, // PIPE_UNLIMITED_INSTANCES, PipeBufSize, PipeBufSize, NMPWAIT_USE_DEFAULT_WAIT, NULL); if (pipe == INVALID_HANDLE_VALUE) rtErrConvertFromWin32OnFailure(); mIsOpen = true; mIsServer = true; mReadEnd = pipe; mWriteEnd = pipe; mName = aName; return VINF_SUCCESS; } int SVCHlpClient::open (const char *aName) { AssertReturn (aName, VERR_INVALID_PARAMETER); if (mIsOpen) return VERR_WRONG_ORDER; Bstr pipeName = Utf8StrFmt ("\\\\.\\pipe\\%s", aName); HANDLE pipe = CreateFile (pipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (pipe == INVALID_HANDLE_VALUE) rtErrConvertFromWin32OnFailure(); mIsOpen = true; mIsServer = false; mReadEnd = pipe; mWriteEnd = pipe; mName = aName; return VINF_SUCCESS; } int SVCHlpClient::connect() { if (!mIsOpen || !mIsServer) return VERR_WRONG_ORDER; BOOL ok = ConnectNamedPipe (mReadEnd, NULL); if (!ok && GetLastError() != ERROR_PIPE_CONNECTED) rtErrConvertFromWin32OnFailure(); return VINF_SUCCESS; } int SVCHlpClient::close() { if (!mIsOpen) return VERR_WRONG_ORDER; if (mWriteEnd != NULL && mWriteEnd != mReadEnd) { if (!CloseHandle (mWriteEnd)) rtErrConvertFromWin32OnFailure(); mWriteEnd = NULL; } if (mReadEnd != NULL) { if (!CloseHandle (mReadEnd)) rtErrConvertFromWin32OnFailure(); mReadEnd = NULL; } mIsOpen = false; mIsServer = false; mName.setNull(); return VINF_SUCCESS; } int SVCHlpClient::write (const void *aVal, size_t aLen) { AssertReturn (aVal != NULL, VERR_INVALID_PARAMETER); AssertReturn (aLen != 0, VERR_INVALID_PARAMETER); if (!mIsOpen) return VERR_WRONG_ORDER; DWORD written = 0; BOOL ok = WriteFile (mWriteEnd, aVal, aLen, &written, NULL); AssertReturn (!ok || written == aLen, VERR_GENERAL_FAILURE); return ok ? VINF_SUCCESS : rtErrConvertFromWin32OnFailure(); } int SVCHlpClient::write (const Utf8Str &aVal) { if (!mIsOpen) return VERR_WRONG_ORDER; /* write -1 for NULL strings */ if (aVal.isNull()) return write ((size_t) ~0); size_t len = aVal.length(); /* write string length */ int vrc = write (len); if (VBOX_SUCCESS (vrc)) { /* write string data */ vrc = write (aVal.raw(), len); } return vrc; } int SVCHlpClient::write (const Guid &aGuid) { Utf8Str guidStr = aGuid.toString(); return write (guidStr); } int SVCHlpClient::read (void *aVal, size_t aLen) { AssertReturn (aVal != NULL, VERR_INVALID_PARAMETER); AssertReturn (aLen != 0, VERR_INVALID_PARAMETER); if (!mIsOpen) return VERR_WRONG_ORDER; DWORD read = 0; BOOL ok = ReadFile (mReadEnd, aVal, aLen, &read, NULL); AssertReturn (!ok || read == aLen, VERR_GENERAL_FAILURE); return ok ? VINF_SUCCESS : rtErrConvertFromWin32OnFailure(); } int SVCHlpClient::read (Utf8Str &aVal) { if (!mIsOpen) return VERR_WRONG_ORDER; size_t len = 0; /* read string length */ int vrc = read (len); if (VBOX_FAILURE (vrc)) return vrc; /* length -1 means a NULL string */ if (len == (size_t) ~0) { aVal.setNull(); return VINF_SUCCESS; } aVal.alloc (len + 1); aVal.mutableRaw() [len] = 0; /* read string data */ vrc = read (aVal.mutableRaw(), len); return vrc; } int SVCHlpClient::read (Guid &aGuid) { Utf8Str guidStr; int vrc = read (guidStr); if (VBOX_SUCCESS (vrc)) aGuid = Guid (guidStr); return vrc; } //////////////////////////////////////////////////////////////////////////////// SVCHlpServer::SVCHlpServer () { } int SVCHlpServer::run() { int vrc = VINF_SUCCESS; SVCHlpMsg::Code msgCode = SVCHlpMsg::Null; do { vrc = read (msgCode); if (VBOX_FAILURE (vrc)) return vrc; /* terminate request received */ if (msgCode == SVCHlpMsg::Null) return VINF_SUCCESS; switch (msgCode) { case SVCHlpMsg::CreateHostNetworkInterface: case SVCHlpMsg::RemoveHostNetworkInterface: { vrc = Host::networkInterfaceHelperServer (this, msgCode); break; } default: AssertMsgFailedReturn (( "Invalid message code %d (%08lX)\n", msgCode, msgCode), VERR_GENERAL_FAILURE); } if (VBOX_FAILURE (vrc)) return vrc; } while (1); /* we never get here */ AssertFailed(); return VERR_GENERAL_FAILURE; }