Vinzenz Feenstra has uploaded a new change for review. Change subject: tray win32 impl ......................................................................
tray win32 impl Change-Id: I3c0caa72b548bb3ce39e06f7dc879709dba89989 Signed-off-by: Vinzenz Feenstra <vfeen...@redhat.com> --- A tray/win32/ovirt-tray/ovirt-tray.sln A tray/win32/ovirt-tray/ovirt-tray/ovirt-tray.cpp A tray/win32/ovirt-tray/ovirt-tray/ovirt-tray.rc A tray/win32/ovirt-tray/ovirt-tray/ovirt-tray.vcproj A tray/win32/ovirt-tray/ovirt-tray/resource.h A tray/win32/ovirt-tray/pipeserver/ReadMe.txt A tray/win32/ovirt-tray/pipeserver/bson.h A tray/win32/ovirt-tray/pipeserver/critical_section.h A tray/win32/ovirt-tray/pipeserver/dllmain.cpp A tray/win32/ovirt-tray/pipeserver/function_storage.h A tray/win32/ovirt-tray/pipeserver/handle.h A tray/win32/ovirt-tray/pipeserver/handler_functions.h A tray/win32/ovirt-tray/pipeserver/handler_impl.h A tray/win32/ovirt-tray/pipeserver/iofunoverlapped.h A tray/win32/ovirt-tray/pipeserver/message.h A tray/win32/ovirt-tray/pipeserver/named_pipe.h A tray/win32/ovirt-tray/pipeserver/pipeserver.cpp A tray/win32/ovirt-tray/pipeserver/pipeserver.h A tray/win32/ovirt-tray/pipeserver/pipeserver.vcproj A tray/win32/ovirt-tray/pipeserver/ref_ptr.h A tray/win32/ovirt-tray/pipeserver/service.h A tray/win32/ovirt-tray/pipeserver/stdafx.cpp A tray/win32/ovirt-tray/pipeserver/stdafx.h A tray/win32/ovirt-tray/pipeserver/stream_service.h A tray/win32/ovirt-tray/pipeserver/targetver.h A tray/win32/ovirt-tray/pipeserver/utilities.h 26 files changed, 3,273 insertions(+), 0 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-guest-agent refs/changes/43/34443/1 diff --git a/tray/win32/ovirt-tray/ovirt-tray.sln b/tray/win32/ovirt-tray/ovirt-tray.sln new file mode 100644 index 0000000..19c7376 --- /dev/null +++ b/tray/win32/ovirt-tray/ovirt-tray.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ovirt-tray", "ovirt-tray\ovirt-tray.vcproj", "{D5C9FA9F-D75A-4090-B8EE-DE271B938FAC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pipeserver", "pipeserver\pipeserver.vcproj", "{A87356ED-7C0B-42CA-9327-E7CDE9C4E481}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D5C9FA9F-D75A-4090-B8EE-DE271B938FAC}.Debug|Win32.ActiveCfg = Debug|Win32 + {D5C9FA9F-D75A-4090-B8EE-DE271B938FAC}.Debug|Win32.Build.0 = Debug|Win32 + {D5C9FA9F-D75A-4090-B8EE-DE271B938FAC}.Debug|x64.ActiveCfg = Debug|x64 + {D5C9FA9F-D75A-4090-B8EE-DE271B938FAC}.Debug|x64.Build.0 = Debug|x64 + {D5C9FA9F-D75A-4090-B8EE-DE271B938FAC}.Release|Win32.ActiveCfg = Release|Win32 + {D5C9FA9F-D75A-4090-B8EE-DE271B938FAC}.Release|Win32.Build.0 = Release|Win32 + {D5C9FA9F-D75A-4090-B8EE-DE271B938FAC}.Release|x64.ActiveCfg = Release|x64 + {D5C9FA9F-D75A-4090-B8EE-DE271B938FAC}.Release|x64.Build.0 = Release|x64 + {A87356ED-7C0B-42CA-9327-E7CDE9C4E481}.Debug|Win32.ActiveCfg = Debug|Win32 + {A87356ED-7C0B-42CA-9327-E7CDE9C4E481}.Debug|Win32.Build.0 = Debug|Win32 + {A87356ED-7C0B-42CA-9327-E7CDE9C4E481}.Debug|x64.ActiveCfg = Debug|x64 + {A87356ED-7C0B-42CA-9327-E7CDE9C4E481}.Debug|x64.Build.0 = Debug|x64 + {A87356ED-7C0B-42CA-9327-E7CDE9C4E481}.Release|Win32.ActiveCfg = Release|Win32 + {A87356ED-7C0B-42CA-9327-E7CDE9C4E481}.Release|Win32.Build.0 = Release|Win32 + {A87356ED-7C0B-42CA-9327-E7CDE9C4E481}.Release|x64.ActiveCfg = Release|x64 + {A87356ED-7C0B-42CA-9327-E7CDE9C4E481}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tray/win32/ovirt-tray/ovirt-tray/ovirt-tray.cpp b/tray/win32/ovirt-tray/ovirt-tray/ovirt-tray.cpp new file mode 100644 index 0000000..4eb45ec --- /dev/null +++ b/tray/win32/ovirt-tray/ovirt-tray/ovirt-tray.cpp @@ -0,0 +1,136 @@ +#include <windows.h> +#include <named_pipe.h> +#include "resource.h" + +#include <strsafe.h> + +#pragma comment(lib, "strsafe.lib") + +UINT WM_TASKBARCREATED; + +static TCHAR const OVIRT_TRAY_CLS[] = TEXT("OVIRT_GUEST_AGENT_TRAY"); + +enum { + WM_NOTIFY_ICON_MESSAGE = WM_USER + 1, + IDT_TIMER = 102030 +}; + +void RegisterWindow(); +LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM); +NOTIFYICONDATA notify = {}; + +Service g_ioService; +NamedPipeStream g_pipe(g_ioService); + +static TCHAR const * const OVIRT_PIPE_NAME = TEXT("\\\\.\\pipe\\ovirt-agent-test"); + +void ConnectPipe() { + if(g_pipe.IsOpen()) { + return; + } + DWORD result = g_pipe.Open(OVIRT_PIPE_NAME); + if(result == NO_ERROR) { + return; + } + else { + g_ioService.Post(ConnectPipe); + ::WaitNamedPipe(OVIRT_PIPE_NAME, 100); + } +} + +int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) +{ + g_ioService.Start(); + g_ioService.Post(ConnectPipe); + + WM_TASKBARCREATED = RegisterWindowMessage(TEXT("TaskbarCreated")); + + RegisterWindow(); + + HWND wnd = CreateWindow(OVIRT_TRAY_CLS, TEXT("ovirt-guest-agent"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, 0, 0, 0, 0); + + notify.cbSize = sizeof(notify); + notify.hWnd = wnd; + notify.hIcon = LoadIcon(0, IDI_APPLICATION); + notify.uCallbackMessage = WM_NOTIFY_ICON_MESSAGE; + StringCchCopy(notify.szTip, 64, TEXT("ovirt-guest-agent")); + notify.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + Shell_NotifyIcon(NIM_ADD, ¬ify); + SetTimer(wnd, IDT_TIMER, 10000, 0); + + MSG message; + while(GetMessage(&message, 0, 0, 0)) { + TranslateMessage(&message); + DispatchMessage(&message); + } + Shell_NotifyIcon(NIM_DELETE, ¬ify); + g_ioService.Stop(); + return 0; +} + +void RegisterWindow() +{ + WNDCLASSEX wcex = {}; + wcex.cbSize = sizeof(wcex); + wcex.lpfnWndProc = (WNDPROC)WindowProc; + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpszClassName = OVIRT_TRAY_CLS; + wcex.hIcon = LoadIcon(0, IDI_APPLICATION); + wcex.hIconSm = LoadIcon(0, IDI_APPLICATION); + wcex.hCursor = LoadCursor(0, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)COLOR_BACKGROUND; + RegisterClassEx(&wcex); +} + +BOOL CALLBACK AboutDlgProc(HWND h, UINT m, WPARAM w, LPARAM l) { + if(m == WM_COMMAND) { + if(LOWORD(w) == IDOK) { + EndDialog(h, w); + return TRUE; + } + } + return FALSE; +} + +LRESULT CALLBACK WindowProc(HWND h, UINT m, WPARAM w, LPARAM l) +{ + if(m == WM_NOTIFY_ICON_MESSAGE) { + if(l == WM_LBUTTONUP) { + MessageBox(0, TEXT("Geez"), TEXT("Click Click"), MB_OK|MB_ICONINFORMATION); + } + else if(l == WM_RBUTTONUP) { + HMENU menu = LoadMenu(0, MAKEINTRESOURCE(IDR_TRAY_MENU)); + menu = GetSubMenu(menu, 0); + POINT pt = {}; + GetCursorPos(&pt); + INT result = TrackPopupMenu(menu, TPM_RETURNCMD, pt.x, pt.y, 0, h, 0); + // TrackPopupMenu() + if(ID_TRAYMENU_ABOUT == result) { + DialogBox(0, MAKEINTRESOURCE(IDD_ABOUT_DIALOG), h, (DLGPROC)(AboutDlgProc)); + } + if(ID_TRAYMENU_QUIT == result) { + if(MessageBox(0, TEXT("Do you really want to quit the oVirt guest agent tray application?"), TEXT("Please confirm"), MB_ICONQUESTION|MB_YESNO) == IDYES) { + PostMessage(h, WM_CLOSE, 0, 0); + } + } + } + return 0; + } + if(m == WM_TIMER) { + switch(w) { + case IDT_TIMER: + { + StringCchCopy(notify.szInfo, 256, TEXT("The ovirt-guest-agent sends a notification")); + StringCchCopy(notify.szInfoTitle, 64, TEXT("ovirt-guest-agent notifies")); + notify.dwInfoFlags = NIIF_INFO; + notify.uFlags |= NIF_INFO; + Shell_NotifyIcon(NIM_MODIFY, ¬ify); + KillTimer(h, IDT_TIMER); + } + } + } + if(m == WM_CLOSE) { + PostQuitMessage(0); + } + return DefWindowProc(h, m, w, l); +} \ No newline at end of file diff --git a/tray/win32/ovirt-tray/ovirt-tray/ovirt-tray.rc b/tray/win32/ovirt-tray/ovirt-tray/ovirt-tray.rc new file mode 100644 index 0000000..86d26f3 --- /dev/null +++ b/tray/win32/ovirt-tray/ovirt-tray/ovirt-tray.rc @@ -0,0 +1,120 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_TRAY_MENU MENU +BEGIN + POPUP "Tray Menu" + BEGIN + MENUITEM "&About", ID_TRAYMENU_ABOUT + MENUITEM SEPARATOR + MENUITEM "&Quit", ID_TRAYMENU_QUIT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT_DIALOG DIALOGEX 0, 0, 316, 183 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About oVirt Guest Tools" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,259,162,50,14 + LTEXT "oVirt Guest Tools for Windows",IDC_GUEST_TOOLS_NAME,7,7,206,8 + LTEXT "Version 3.6.0",IDC_GUEST_TOOLS_VERSION,7,21,206,8 + ICON 32512,IDC_GUEST_TOOLS_ICON,284,7,20,20 + EDITTEXT IDC_LICENSE_TEXT,7,38,302,117,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY,WS_EX_CLIENTEDGE + LTEXT "The oVirt Guest Tools are running.",IDC_GUEST_STATUS,7,168,205,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUT_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 309 + TOPMARGIN, 7 + BOTTOMMARGIN, 176 + HORZGUIDE, 7 + HORZGUIDE, 21 + HORZGUIDE, 30 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/tray/win32/ovirt-tray/ovirt-tray/ovirt-tray.vcproj b/tray/win32/ovirt-tray/ovirt-tray/ovirt-tray.vcproj new file mode 100644 index 0000000..0a80ec2 --- /dev/null +++ b/tray/win32/ovirt-tray/ovirt-tray/ovirt-tray.vcproj @@ -0,0 +1,355 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="ovirt-tray" + ProjectGUID="{D5C9FA9F-D75A-4090-B8EE-DE271B938FAC}" + RootNamespace="ovirttray" + Keyword="Win32Proj" + TargetFrameworkVersion="196613" + > + <Platforms> + <Platform + Name="Win32" + /> + <Platform + Name="x64" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(ProjectDir)\..\pipeserver" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="2" + GenerateDebugInformation="true" + SubSystem="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + EnableIntrinsicFunctions="true" + AdditionalIncludeDirectories="$(ProjectDir)\..\pipeserver" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS" + RuntimeLibrary="0" + EnableFunctionLevelLinking="true" + UsePrecompiledHeader="0" + WarningLevel="3" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="1" + GenerateDebugInformation="true" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|x64" + OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(ProjectDir)\..\pipeserver" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="2" + GenerateDebugInformation="true" + SubSystem="2" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + EnableIntrinsicFunctions="true" + AdditionalIncludeDirectories="$(ProjectDir)\..\pipeserver" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS" + RuntimeLibrary="0" + EnableFunctionLevelLinking="true" + UsePrecompiledHeader="0" + WarningLevel="3" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="1" + GenerateDebugInformation="true" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath=".\ovirt-tray.cpp" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath=".\resource.h" + > + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + <File + RelativePath=".\ovirt-tray.rc" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/tray/win32/ovirt-tray/ovirt-tray/resource.h b/tray/win32/ovirt-tray/ovirt-tray/resource.h new file mode 100644 index 0000000..05be8ca --- /dev/null +++ b/tray/win32/ovirt-tray/ovirt-tray/resource.h @@ -0,0 +1,24 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ovirt-tray.rc +// +#define IDR_TRAY_MENU 101 +#define IDD_ABOUT_DIALOG 102 +#define IDC_LICENSE_TEXT 1001 +#define IDC_GUEST_TOOLS_VERSION 1002 +#define IDC_GUEST_STATUS 1003 +#define IDC_GUEST_TOOLS_ICON 1004 +#define IDC_GUEST_TOOLS_NAME 1005 +#define ID_TRAYMENU_ABOUT 40001 +#define ID_TRAYMENU_QUIT 40002 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40003 +#define _APS_NEXT_CONTROL_VALUE 1006 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/tray/win32/ovirt-tray/pipeserver/ReadMe.txt b/tray/win32/ovirt-tray/pipeserver/ReadMe.txt new file mode 100644 index 0000000..3d56182 --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/ReadMe.txt @@ -0,0 +1,33 @@ +======================================================================== + DYNAMIC LINK LIBRARY : pipeserver Project Overview +======================================================================== + +AppWizard has created this pipeserver DLL for you. + +This file contains a summary of what you will find in each of the files that +make up your pipeserver application. + + +pipeserver.vcproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +pipeserver.cpp + This is the main DLL source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named pipeserver.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/tray/win32/ovirt-tray/pipeserver/bson.h b/tray/win32/ovirt-tray/pipeserver/bson.h new file mode 100644 index 0000000..166ddd6 --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/bson.h @@ -0,0 +1,635 @@ +#pragma once + +#include <string> +#include <vector> +#include <unordered_map> +#include <memory> +#include <cassert> +#include "ref_ptr.h" + +struct null_t{}; +namespace detail { + typedef unsigned char uint8_t; + typedef INT32 int32_t; + typedef INT64 int64_t; + + + /* Basic types: All values are little endian encoded + * <uint8> 1 byte (8-bit unsigned integer, two's complement) + * <int32> 4 bytes (32-bit signed integer, two's complement) + * <int64> 8 bytes (64-bit signed integer, two's complement) + * <double> 8 bytes (64-bit IEEE 754 floating point) + * + * document ::= size value + * value: ::= + * byte + * | bool + * | int32 + * | int64 + * | double + * | string + * | list + * | object + * | map + * | binary + * | datetime + * | null + * null ::= '\x00' # + * byte ::= '\x01' <uint8> # + * bool ::= '\x02' ('\x00' | '\x01') # '\x00' when false, '\x01' when true + * int32 ::= '\x03' <int32> # + * int64 ::= '\x04' <int64> # + * double ::= '\x05' <double> # + * string ::= '\x06' size cstring # size must match the number of elements in cstring including 0 termination + * list ::= '\x07' size value* # size must match the number of value elements + * object ::= '\x08' size (string value)* # size must match the number of (string value) tuples + * map ::= '\x09' size (value value)* # size must match the number of (value value) tuples + * binary ::= '\x0A' size <uint8>* # size must match count of <uint8> elements + * datetime ::= '\x0B' size int64_t # seconds since UTC epoch + * cstring ::= <uint8>* '\x00' # 0-terminated utf-8 encoded string + * size ::= <int64> + */ + + enum data_type { + kDataType_First = 0x00, + kDataType_Null = 0x00, + kDataType_Byte = 0x01, + kDataType_Bool = 0x02, + kDataType_Int32 = 0x03, + kDataType_Int64 = 0x04, + kDataType_Double = 0x05, + kDataType_String = 0x06, + kDataType_List = 0x07, + kDataType_Object = 0x08, + kDataType_Map = 0x09, + kDataType_Binary = 0x0A, + kDataType_DateTime = 0x0B, + + // Leave at end + kDataType_Count, + kDataType_Last = kDataType_Count - 1, + kDataType_Invalid = -1 + }; + + template< typename T > + void push(std::vector<uint8_t> & target, T v) { + uint8_t const * ptr = reinterpret_cast<uint8_t const *>(&v); + target.insert(target.end(), ptr, ptr + sizeof(v)); + } + + template< typename T > + void push(std::vector<uint8_t> & target, T const * tptr, size_t elements) { + uint8_t const * ptr = reinterpret_cast<uint8_t const *>(ptr); + target.insert(target.end(), ptr, ptr + (sizeof(T) * elements)); + } + + template< typename Element, size_t SizeDiff > + class data_view { + public: + typedef Element value_type; + typedef value_type const * iterator; + typedef value_type const * const_iterator; + typedef value_type const * const_pointer; + typedef size_t size_type; + static Element const EMPTY = 0; + + data_view() + : p_(&EMPTY) + , length_(0) + {} + + data_view(const_pointer b, const_pointer e) + : p_(b) + , length_(size_type(e - b) >= SizeDiff ? size_type(e - b) - SizeDiff : 0) + { + assert(b <= e); + } + + data_view(data_view const & that) + : p_(that.p_) + , length_(that.length_) + {} + + value_type operator[](size_type index) const { + assert(index < length_); + return p_[index]; + } + + const_iterator begin() const { + return p_; + } + + const_iterator end() const { + return p_ + length_; + } + + size_type size() const { + return length_; + } + + const_pointer data() const { + return p_; + } + + size_t diff() const { + return SizeDiff; + } + protected: + const_pointer p_; + size_type length_; + }; + + typedef data_view<uint8_t, 0> binary_view; + + class string_view : public data_view<char, 1> { + public: + string_view() + : data_view() + {} + + string_view(const_pointer b, const_pointer e) + : data_view(b, e) + {} + + const_pointer c_str() const { + return data(); + } + }; + + class value { + protected: + // Only inheriting classes are + // allowed to set the type + value(data_type type) + : type_(type) + {} + public: + value() + : type_(kDataType_Invalid) + {} + + data_type type() const { + return type_; + } + + bool valid() const { + return type_ != kDataType_Invalid + && type_ >= kDataType_First + && type_ <= kDataType_Last + ; + } + + bool operator==(value const & rhs) const { + return equals(rhs); + } + + virtual void append(std::vector<uint8_t> & target) const = 0; + virtual bool equals(value const & rhs) const = 0; + virtual size_t hash() const = 0; + protected: + data_type const type_; + }; + + typedef ref_ptr<value> value_ptr; + + bool consume(uint8_t const *& b, uint8_t const * e, uint8_t & target) { + return false; + } + bool consume(uint8_t const *& b, uint8_t const * e, int32_t & target) { + return false; + } + bool consume(uint8_t const *& b, uint8_t const * e, int64_t & target) { + return false; + } + bool consume(uint8_t const *& b, uint8_t const * e, double & target) { + return false; + } + bool consume(uint8_t const *& b, uint8_t const * e, value_ptr & target); + + template< typename T > + bool consume(uint8_t const *& b, uint8_t const * e, ref_ptr<T> & target) { + return T::consume(b, e, target); + } + + class null_value : public value { + public: + null_value() + : value(kDataType_Null) + {} + + null_value(null_t const &) + : value(kDataType_Null) + {} + + static bool consume(uint8_t const *& b, + uint8_t const * e, + ref_ptr<null_value> & target); + void append(std::vector<uint8_t> & target) const { + push<uint8_t>(target, type()); + } + bool equals(value const & rhs) const { + return true; + } + size_t hash() const { return 0; } + }; + + template< typename PODType, data_type DataType > + class basic_pod_value : public value { + public: + typedef value base_type; + basic_pod_value(PODType v = PODType()) + : base_type(DataType) + , data_(v) + {} + + PODType value() const { + return data_; + } + + void value(PODType v) { + data_ = v; + } + + static bool consume(uint8_t const *& b, + uint8_t const * e, + ref_ptr<basic_pod_value> & target); + void append(std::vector<uint8_t> & target) const { + push<uint8_t>(target, DataType); + push<PODType>(target, data_); + } + bool equals(base_type const & rhs) const { + return rhs.type() == type() + && data_ == static_cast<basic_pod_value const &>(rhs).data_; + } + size_t hash() const { + return std::tr1::hash<PODType>()(data_); + } + protected: + PODType data_; + }; + + typedef basic_pod_value<double, kDataType_Double> double_value; + typedef basic_pod_value<uint8_t, kDataType_Byte> byte_value; + typedef basic_pod_value<int32_t, kDataType_Int32> int32_value; + typedef basic_pod_value<int64_t, kDataType_Int64> int64_value; + typedef basic_pod_value<int64_t, kDataType_DateTime> datetime_value; + + template< typename ViewType, data_type DataType > + class basic_view_value : public value { + public: + typedef value base_type; + basic_view_value(ViewType view) + : base_type(DataType) + , data_(view) + {} + + ViewType value() const { + return data_; + } + + void value(ViewType v) { + data_ = v; + } + + static bool consume(uint8_t const *& b, + uint8_t const * e, + ref_ptr<basic_view_value> & target) + { + uint8_t const * const backup = b; + bool result = false; + if(b < e) { + uint8_t t = kDataType_Invalid; + result = detail::consume(b, e, t) && t == DataType; + int64_t count = 0; + result = result && detail::consume(b, e, count); + result = (e - b) <= count; + if(result) { + typedef ViewType::const_pointer ptr_t; + target = new basic_view_value(ViewType(reinterpret_cast<ptr_t>(b), reinterpret_cast<ptr_t>(b) + count)); + } + } + if(!result) { + b = backup; + } + return result; + } + void append(std::vector<uint8_t> & target) const { + push<uint8_t>(target, type()); + push<int64_t>(target, data_.size() + data_.diff()); + if(data_.size() > 0) { + push(target, data_.data(), data_.size() + data_.diff()); + } + } + + bool equals(base_type const & rhs) const { + return type() == rhs.type() + && static_cast<basic_view_value const &>(rhs).value().data() == value().data(); + } + + size_t hash() const { + return std::tr1::hash<typename ViewType::const_pointer>()(data_.data()); + } + protected: + ViewType data_; + }; + + typedef basic_view_value<string_view, kDataType_String> string_value; + typedef basic_view_value<binary_view, kDataType_Binary> binary_value; + + class list_value : public value { + public: + typedef value base_type; + + list_value(std::vector<value_ptr> const & v) + : base_type(kDataType_List) + , data_(new std::vector<value_ptr>(v)) + {} + + list_value(ref_ptr<std::vector<value_ptr> > const & v) + : base_type(kDataType_List) + , data_(v) + {} + + list_value() + : base_type(kDataType_List) + , data_() + {} + + ref_ptr<std::vector<value_ptr> > value() const { + return data_; + } + + void value(std::vector<value_ptr> const & v) { + data_ = new std::vector<value_ptr>(v); + } + + static bool consume(uint8_t const *& b, + uint8_t const * e, + ref_ptr<list_value> & target) + { + ref_ptr<list_value> list; + bool result = false; + uint8_t const * backup = b; + if(b < e) { + uint8_t type8 = kDataType_Invalid; + result = detail::consume(b, e, type8); + int64_t count = 0; + result = result && detail::consume(b, e, count); + list = new list_value(); + list->data_->resize(size_t(count)); + for(int64_t i = 0; result && i < count; ++i) { + result = detail::consume(b, e, (*list->data_)[i]); + } + } + if(!result) { + b = backup; + } + else { + target = list; + } + return result; + } + + void append(std::vector<uint8_t> & target) const { + push<uint8_t>(target, type()); + push<int64_t>(target, data_->size()); + for(std::vector<value_ptr>::const_iterator it = data_->begin(), end = data_->end(); it != end; ++it) { + (*it)->append(target); + } + } + + bool equals(base_type const & rhs) const { + return rhs.type() == type() + && data_.get() != 0 + && static_cast<list_value const &>(rhs).data_.get() != 0 + && (data_.get()) == static_cast<list_value const &>(rhs).data_.get(); + } + + size_t hash() const { + return size_t(data_.get()); + } + protected: + ref_ptr<std::vector<value_ptr> > data_; + }; + + struct value_hasher { + size_t operator()(value_ptr const & v) const { + size_t result = 0; + if(v.get() && v->valid()) { + result = v->hash(); + } + return result; + } + }; + + struct value_equals + : public std::binary_function<value_ptr, value_ptr, bool> { + bool operator()(value_ptr const & lhs, value_ptr const & rhs) const { + bool result = false; + if((lhs.get() != 0) == (rhs.get() != 0)) { + if(lhs.get() != 0 && rhs.get() != 0) { + if(lhs->type() == rhs->type()) { + return *lhs == *rhs; + } + } + } + return result; + }; + }; + + template< typename Key > + class mapped_value : public value { + public: + typedef Key key_type; + typedef value_ptr value_type; + typedef std::tr1::unordered_map<key_type, value_type, value_hasher, value_equals> map_type; + typedef value base_type; + + mapped_value(map_type const & v) + : base_type(kDataType_List) + , data_(new map_type(v)) + {} + + mapped_value(ref_ptr<map_type> const & v) + : base_type(kDataType_List) + , data_(v) + {} + + mapped_value() + : base_type(kDataType_List) + , data_() + {} + + ref_ptr<map_type> value() const { + return data_; + } + + void value(map_type const & v) { + data_ = new map_type(v); + } + + static bool consume(uint8_t const *& b, + uint8_t const * e, + ref_ptr<mapped_value> & target) + { + ref_ptr<mapped_value> map; + bool result = false; + uint8_t const * backup = b; + if(b < e) { + uint8_t type8 = kDataType_Invalid; + result = detail::consume(b, e, type8); + int64_t count = 0; + result = result && detail::consume(b, e, count); + map = new mapped_value(); + for(int64_t i = 0; result && i < count; ++i) { + key_type k; + result = result && detail::consume(b, e, k); + value_type v; + result = result && detail::consume(b, e, v); + (*map->data_)[k] = v; + } + } + if(!result) { + b = backup; + } + else { + target = map; + } + return result; + } + + void append(std::vector<uint8_t> & target) const { + push<int64_t>(target, type()); + push<int64_t>(target, data_->size()); + for(map_type::const_iterator it = data_->begin(), end = data_->end(); it != end; ++it) { + it->first->append(target); + it->second->append(target); + } + } + bool equals(base_type const & rhs) const { + return rhs.type() == type() + && data_.get() != 0 + && static_cast<mapped_value const &>(rhs).data_.get() != 0 + && (data_.get()) == static_cast<mapped_value const &>(rhs).data_.get(); + } + + size_t hash() const { + return size_t(data_.get()); + } + protected: + ref_ptr<map_type> data_; + }; + + typedef mapped_value<ref_ptr<string_value> > object_value; + typedef mapped_value<value_ptr> map_value; + + + bool consume(uint8_t const *& b, uint8_t const * e, value_ptr & target) { + bool result = b < e; + if(result) { + switch(*b) { + case kDataType_Binary: + { + ref_ptr<binary_value> starget; + result = binary_value::consume(b, e, starget); + if(result) { + target = starget; + } + } + break; + case kDataType_Byte: + { + ref_ptr<byte_value> starget; + result = byte_value::consume(b, e, starget); + if(result) { + target = starget; + } + } + break; + case kDataType_DateTime: + { + ref_ptr<datetime_value> starget; + result = datetime_value::consume(b, e, starget); + if(result) { + target = starget; + } + } + break; + case kDataType_Double: + { + ref_ptr<double_value> starget; + result = double_value::consume(b, e, starget); + if(result) { + target = starget; + } + } + break; + case kDataType_Int32: + { + ref_ptr<int32_value> starget; + result = int32_value::consume(b, e, starget); + if(result) { + target = starget; + } + } + break; + case kDataType_Int64: + { + ref_ptr<int64_value> starget; + result = int64_value::consume(b, e, starget); + if(result) { + target = starget; + } + } + break; + case kDataType_List: + { + ref_ptr<list_value> starget; + result = list_value::consume(b, e, starget); + if(result) { + target = starget; + } + } + break; + case kDataType_Map: + { + ref_ptr<map_value> starget; + result = map_value::consume(b, e, starget); + if(result) { + target = starget; + } + } + break; + case kDataType_Null: + { + ref_ptr<null_value> starget; + result = null_value::consume(b, e, starget); + if(result) { + target = starget; + } + } + break; + case kDataType_Object: + { + ref_ptr<object_value> starget; + result = object_value::consume(b, e, starget); + if(result) { + target = starget; + } + } + break; + case kDataType_String: + { + ref_ptr<string_value> starget; + result = string_value::consume(b, e, starget); + if(result) { + target = starget; + } + } + break; + } + } + return false; + } +} + diff --git a/tray/win32/ovirt-tray/pipeserver/critical_section.h b/tray/win32/ovirt-tray/pipeserver/critical_section.h new file mode 100644 index 0000000..c5a5d6e --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/critical_section.h @@ -0,0 +1,48 @@ +#pragma once + +#include <windows.h> + +struct CriticalSection : CRITICAL_SECTION { + class Lock { + CriticalSection * cs_; + public: + Lock(CriticalSection & cs) + : cs_(&cs) + { + cs_->Accquire(); + } + + ~Lock() { + Release(); + } + + void Release() { + if (cs_) { + cs_->Release(); + } + cs_ = 0; + } + }; + + CriticalSection() + : CRITICAL_SECTION() + { + ::InitializeCriticalSection(this); + } + + ~CriticalSection() { + ::DeleteCriticalSection(this); + } + + bool TryAccquire() { + return ::TryEnterCriticalSection(this) == TRUE; + } + + void Accquire() { + ::EnterCriticalSection(this); + } + + void Release() { + ::LeaveCriticalSection(this); + } +}; diff --git a/tray/win32/ovirt-tray/pipeserver/dllmain.cpp b/tray/win32/ovirt-tray/pipeserver/dllmain.cpp new file mode 100644 index 0000000..69b5891 --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/dllmain.cpp @@ -0,0 +1,19 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/tray/win32/ovirt-tray/pipeserver/function_storage.h b/tray/win32/ovirt-tray/pipeserver/function_storage.h new file mode 100644 index 0000000..912b44e --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/function_storage.h @@ -0,0 +1,42 @@ +#pragma once + + +struct FunctionStorage { + struct X {}; + union { + struct { + void * Object; + int (X::*Method)(); + } MPtr; + int(*FunPtr) (); + char Static[32]; + void * Dynamic; + } Data; +}; + + +inline FunctionStorage MakeStorage(void(*f)()) { + FunctionStorage s; + s.Data.FunPtr = reinterpret_cast<int(*)()>(f); + return s; +} + +template< typename F > +inline FunctionStorage MakeStorage(F f) { + FunctionStorage s; + if (sizeof(f) <= sizeof(s.Data.Static)) { + new (&s.Data.Static) F(f); + } + else { + s.Data.Dynamic = new F(f); + } + return s; +} + +template< typename ClassT, typename MethodT > +inline FunctionStorage MakeStorage(ClassT * o, MethodT m) { + FunctionStorage s; + s.Data.MPtr.Object = o; + s.Data.MPtr.Method = reinterpret_cast<int(FunctionStorage::X::*)()>(m); + return s; +} diff --git a/tray/win32/ovirt-tray/pipeserver/handle.h b/tray/win32/ovirt-tray/pipeserver/handle.h new file mode 100644 index 0000000..6f94115 --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/handle.h @@ -0,0 +1,53 @@ +#pragma once + +#include <windows.h> +#include <algorithm> + +struct Handle { + + Handle(HANDLE h = INVALID_HANDLE_VALUE, bool auto_close = false) + : handle_(h) + , auto_close_(auto_close) + {} + + ~Handle() { + if (auto_close_) { + Close(); + } + } + + void Close() { + if (IsValid()) { + ::CloseHandle(handle_); + handle_ = 0; + } + } + + bool IsValid() const { + return handle_ != INVALID_HANDLE_VALUE + && handle_ != 0; + } + + operator bool() const { + return IsValid(); + } + + operator HANDLE() const { + return handle_; + } + + void Swap(Handle & other) { + std::swap(other.auto_close_, auto_close_); + std::swap(other.handle_, handle_); + } + +protected: + bool auto_close_; + HANDLE handle_; +}; + +struct AutoHandle : Handle { + AutoHandle(HANDLE h) + : Handle(h, true) + {} +}; diff --git a/tray/win32/ovirt-tray/pipeserver/handler_functions.h b/tray/win32/ovirt-tray/pipeserver/handler_functions.h new file mode 100644 index 0000000..0e0b76e --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/handler_functions.h @@ -0,0 +1,87 @@ +#pragma once + +#include "handler_impl.h" + +struct IOHandler { + IOHandler() + : storage_() + , handler_(0) + {} + + IOHandler(IOHandler const & other) + : storage_(other ? other.handler_().Clone(other.storage_) : FunctionStorage()) + , handler_(other.handler_) + {} + + template< typename F > + IOHandler(F f) + : storage_(MakeStorage(f)) + , handler_(MakeHandlerFun<HandlerT>::Get(f)) + {} + + template< typename ClassT, typename MethodT > + IOHandler(ClassT * o, MethodT * m) + : storage_(MakeStorage(o, m)) + , handler_(MakeHandlerFun<HandlerT>::Get(o, m)) + {} + + ~IOHandler() { + if (handler_) { + handler_().Release(storage_); + } + } + + operator bool() const { + return handler_ != 0; + } + + void operator()(DWORD err, DWORD trans){ + handler_().Call(storage_, err, trans); + } +protected: + typedef FunctionHandlers<void(*)(FunctionStorage&, DWORD, DWORD)> HandlerT; + FunctionStorage storage_; + HandlerT (*handler_)(); +}; + +struct CompletionHandler { + CompletionHandler() + : storage_() + , handler_(0) + {} + + CompletionHandler(CompletionHandler const & other) + : storage_(other ? other.handler_().Clone(other.storage_) : FunctionStorage()) + , handler_(other.handler_) + {} + + template< typename F > + CompletionHandler(F f) + : storage_(MakeStorage(f)) + , handler_(MakeHandlerFun<HandlerT>::Get(f)) + {} + + template< typename ClassT, typename MethodT > + CompletionHandler(ClassT * o, MethodT m) + : storage_(MakeStorage(o, m)) + , handler_(MakeHandlerFun<HandlerT>::Get(o, m)) + {} + + ~CompletionHandler() { + if (handler_) { + handler_().Release(storage_); + } + } + + operator bool() const { + return handler_ != 0; + } + + void operator()(){ + handler_().Call(storage_); + } +protected: + typedef FunctionHandlers<void(*)(FunctionStorage&)> HandlerT; + FunctionStorage storage_; + HandlerT(*handler_)(); +}; \ No newline at end of file diff --git a/tray/win32/ovirt-tray/pipeserver/handler_impl.h b/tray/win32/ovirt-tray/pipeserver/handler_impl.h new file mode 100644 index 0000000..dd4a900 --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/handler_impl.h @@ -0,0 +1,140 @@ +#pragma once + +#include "function_storage.h" + +template< typename CallSignature > +struct FunctionHandlers { + typedef CallSignature CallSignatureType; + + CallSignature Call; + void(*Release)(FunctionStorage &); + FunctionStorage(*Clone)(FunctionStorage const &); +}; + +template< typename T > +struct GenFun { + typedef T(*Type)(); +}; + +FunctionStorage SimpleClone(FunctionStorage const & s) { + return s; +} + +template< typename T > +FunctionStorage FunctorClone(FunctionStorage const & s) { + FunctionStorage tmp = {}; + if (sizeof(T) <= sizeof(s.Data.Static)) { + new (tmp.Data.Static) T(*reinterpret_cast<T const*>(s.Data.Static)); + } + else { + tmp.Data.Dynamic = new(std::nothrow) T(*reinterpret_cast<T const*>(s.Data.Dynamic)); + } + return tmp; +} + +void SimpleRelease(FunctionStorage&){} + +template< typename T > +void FunctorRelease(FunctionStorage & s) { + if (sizeof(T) <= sizeof(s.Data.Static)) { + reinterpret_cast<T*>(s.Data.Static)->~T(); + } + else { + delete reinterpret_cast<T*>(s.Data.Dynamic); + } +} + +template< typename SignatureT > +struct CallerImpl; + +template< typename HandlerT > +HandlerT FunctionHandler() { + static HandlerT tmp = { + &CallerImpl<typename HandlerT::CallSignatureType>::Function, + &SimpleRelease, + &SimpleClone + }; + return tmp; +}; + +template< typename HandlerT, typename FunctorT > +HandlerT FunctorHandler() { + static HandlerT tmp = { + &CallerImpl<typename HandlerT::CallSignatureType>::Functor<FunctorT>, + &FunctorRelease<FunctorT>, + &FunctorClone<FunctorT> + }; + return tmp; +}; + +template< typename HandlerT, typename ClassT, typename MethodT > +HandlerT MethodHandler() { + static HandlerT tmp = { + &CallerImpl<typename HandlerT::CallSignatureType>::Method<ClassT, MethodT>, + &SimpleRelease, + &SimpleClone + }; + return tmp; +}; + +template< typename HandlerT > +struct MakeHandlerFun { + template< typename ClassT, typename MethodT > + static typename GenFun<HandlerT>::Type Get(ClassT * o, MethodT m) + { + // Method + return MethodHandler<HandlerT, ClassT, MethodT>; + } + + static typename GenFun<HandlerT>::Type Get(typename HandlerT::CallSignatureType f) { + // Function + return FunctionHandler<HandlerT>; + } + + template< typename F > + static typename GenFun<HandlerT>::Type Get(F f) + { + // Functor + return FunctorHandler<HandlerT, F>; + } +}; + +template<> +struct CallerImpl<void(*)(FunctionStorage&, DWORD, DWORD)> { + static void Function(FunctionStorage&s, DWORD e, DWORD t) { + reinterpret_cast<void(*)(DWORD, DWORD)>(s.Data.FunPtr)(e, t); + } + template< typename C, typename M> + static void Method(FunctionStorage&s, DWORD e, DWORD t) { + ((*reinterpret_cast<C*>(s.Data.MPtr.Object)).*reinterpret_cast<M>(s.Data.MPtr.Method))(e, t); + } + template< typename C > + static void Functor(FunctionStorage&s, DWORD e, DWORD t) { + if (sizeof(C) <= sizeof(s.Data.Static)) { + (*reinterpret_cast<C*>(s.Data.Static))(e, t); + } + else { + (*reinterpret_cast<C*>(s.Data.Dynamic))(e, t); + } + } +}; + +template<> +struct CallerImpl<void(*)(FunctionStorage&)> { + static void Function(FunctionStorage&s) { + reinterpret_cast<void(*)()>(s.Data.FunPtr)(); + } + template< typename C, typename M> + static void Method(FunctionStorage&s) { + ((*reinterpret_cast<C*>(s.Data.MPtr.Object)).*reinterpret_cast<M>(s.Data.MPtr.Method))(); + } + template< typename C > + static void Functor(FunctionStorage&s) { + if (sizeof(C) <= sizeof(s.Data.Static)) { + (*reinterpret_cast<C*>(s.Data.Static))(); + } + else { + (*reinterpret_cast<C*>(s.Data.Dynamic))(); + } + } +}; diff --git a/tray/win32/ovirt-tray/pipeserver/iofunoverlapped.h b/tray/win32/ovirt-tray/pipeserver/iofunoverlapped.h new file mode 100644 index 0000000..34a7c42 --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/iofunoverlapped.h @@ -0,0 +1,49 @@ +#pragma once + +#include "critical_section.h" +#include "handler_functions.h" +#include "handle.h" + +struct IOFunOverlapped : OVERLAPPED { + int References; + IOHandler Callable; + bool Called; + CriticalSection Sync; + + IOFunOverlapped(IOHandler callable) + : OVERLAPPED() + , References(1) + , Callable(callable) + , Called(false) + , Sync() + { + hEvent = CreateEvent(0, TRUE, FALSE, 0); + } + + ~IOFunOverlapped() { + ::CloseHandle(hEvent); + } + + void AddRef() { + CriticalSection::Lock lock(Sync); + References += 1; + } + + void Release() { + bool del = false; + { + CriticalSection::Lock lock(Sync); + References -= 1; + del = References < 1; + } + if(del) delete this; + } + + void Perform(DWORD error, DWORD trans) { + CriticalSection::Lock lock(Sync); + if (!Called && Callable) { + Called = true; + Callable(error, trans); + } + } +}; diff --git a/tray/win32/ovirt-tray/pipeserver/message.h b/tray/win32/ovirt-tray/pipeserver/message.h new file mode 100644 index 0000000..8a22df5 --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/message.h @@ -0,0 +1,18 @@ +#pragma once + +struct MessageEntry { + UINT32 Length; + char const * Value; +}; + +struct MessageField { + MessageEntry Key; + MessageEntry Value; +}; + +struct Message { + UINT32 BodySize; + UINT32 FieldCount; + MessageField * Fields; +}; + diff --git a/tray/win32/ovirt-tray/pipeserver/named_pipe.h b/tray/win32/ovirt-tray/pipeserver/named_pipe.h new file mode 100644 index 0000000..0afa98c --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/named_pipe.h @@ -0,0 +1,134 @@ +#pragma once + +#include <string> +#include "stream_service.h" + + + +struct NamedPipeService : StreamService { + NamedPipeService(Service & service) + : StreamService(service) + {} + + void Close(Handle & h) { + ::DisconnectNamedPipe(h); + StreamService::Close(h); + } + + DWORD Open(Handle & h, TCHAR const * path) { + DWORD result = StreamService::Open(h, path); + if (result == NO_ERROR) { + DWORD mode = PIPE_READMODE_BYTE; + if (!::SetNamedPipeHandleState(h, &mode, NULL, NULL)) { + result = GetLastError(); + Close(h); + } + } + return result; + } +}; + +typedef BasicStream<NamedPipeService> NamedPipeStream; + +struct NamedPipeAcceptor; +struct NamedPipeAcceptor { + NamedPipeAcceptor(Service & service) + : service_(service) + , buffer_size_(0x10000) + , name_() + , attributes_(0) + , stream_(service) + {} + + ~NamedPipeAcceptor() { + Close(); + } + + DWORD Open(std::basic_string<TCHAR> const & name, LPSECURITY_ATTRIBUTES attributes = 0) { + Close(); + name_ = TEXT("\\\\.\\pipe\\") + name; + attributes_ = attributes; + return Create(stream_); + } + + bool IsOpen() const { + return !name_.empty(); + } + + void Close() { + name_.clear(); + stream_.Close(); + attributes_ = 0; + } + + DWORD AsyncAccept(NamedPipeStream & stream, IOHandler handler) { + DWORD result = NO_ERROR; + IOFunOverlapped * overlapped = new IOFunOverlapped(handler); + + if (!stream_.IsOpen()) { + result = Create(stream_); + } + if (!result) { + stream.Swap(stream_); + overlapped->AddRef(); + BOOL connected = ::ConnectNamedPipe(stream.Native(), overlapped); + if (!connected) { + result = GetLastError(); + switch (result) + { + case ERROR_PIPE_CONNECTED: + overlapped->AddRef(); + service_.PostCompletionStatus(NO_ERROR, 0, overlapped); + result = NO_ERROR; + break; + case ERROR_IO_PENDING: + result = NO_ERROR; + break; + default: + ::FlushFileBuffers(stream.Native()); + ::DisconnectNamedPipe(stream.Native()); + case ERROR_NO_DATA: + if (stream.Native()) { + stream.Close(); + } + service_.PostCompletionStatus(result, 0, overlapped); + break; + } + } + } + overlapped->Release(); + return result; + } +protected: + DWORD Create(NamedPipeStream & stream) { + Handle h = ::CreateNamedPipe( + name_.c_str(), + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + buffer_size_, + buffer_size_, + NMPWAIT_USE_DEFAULT_WAIT, + attributes_ + ); + if (!h) { + return GetLastError(); + } + if (!service_.Register(h)) { + h.Close(); + return GetLastError(); + } + stream.Assign(h); + return ERROR_SUCCESS; + } +private: + NamedPipeAcceptor(NamedPipeAcceptor const &); + NamedPipeAcceptor & operator=(NamedPipeAcceptor const &); +protected: + Service & service_; + DWORD buffer_size_; + std::basic_string<TCHAR> name_; + LPSECURITY_ATTRIBUTES attributes_; + NamedPipeStream stream_; +}; + diff --git a/tray/win32/ovirt-tray/pipeserver/pipeserver.cpp b/tray/win32/ovirt-tray/pipeserver/pipeserver.cpp new file mode 100644 index 0000000..8cdff4f --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/pipeserver.cpp @@ -0,0 +1,393 @@ +// pipeserver.cpp : Defines the exported functions for the DLL application. +// + +#include "stdafx.h" +#include "pipeserver.h" +#include "named_pipe.h" +#include "message.h" +#include "bson.h" + +struct ClientSendHandler { + PipeConnection * connection; + std::vector<BYTE> * message; + void * userData; + OnMessageCompleted onCompletion; + ClientSendHandler(PipeConnection * connection, Message * message, void * userData, OnMessageCompleted onCompletion) + : connection(connection) + , message(new (std::nothrow) std::vector<BYTE>()) + , userData(userData) + , onCompletion(onCompletion) + { + ConvertToBuffer(message); + } +private: + void AppendEntry(MessageEntry & entry) { + size_t idx = message->size(); + message->insert(message->end(), 4, 0); + *reinterpret_cast<UINT32*>(&(*message)[idx]) = entry.Length; + message->insert(message->end(), entry.Value, entry.Value + entry.Length); + } + + void AppendField(MessageField & field) { + AppendEntry(field.Key); + AppendEntry(field.Value); + } + + void ConvertToBuffer(Message * m) { + message->resize(sizeof(UINT32)* 2, 0); + for(UINT32 i = 0; i < m->FieldCount; ++i) { + AppendField(m->Fields[i]); + } + UINT32 * hdr = reinterpret_cast<UINT32*>(&(*message)[0]); + hdr[0] = UINT32(message->size() - (sizeof(UINT32) * 2)); + hdr[1] = m->FieldCount; + } +public: + BYTE const * buffer() const { + if(bufferLength() == 0) { + return 0; + } + return reinterpret_cast<BYTE const *>(&(*message)[0]); + } + + DWORD bufferLength() const { + if(!message) { + return 0; + } + return DWORD(message->size()); + } + + void operator()(DWORD err, DWORD trans) { + delete message; + message = 0; + if(onCompletion) { + onCompletion(connection, trans, HRESULT_FROM_WIN32(err), userData); + } + } +}; + +struct AcceptResultHandler { + PipeServer * server; + PipeConnection * connection; + AcceptResultHandler(PipeServer *, PipeConnection *); + + void operator()(DWORD err, DWORD trans); +}; + + +struct PipeConnection { + NamedPipeStream conn; + PipeServer * server; + + PipeConnection(PipeServer * server); + ~PipeConnection(){ + Close(); + } + void Close(); +}; + +struct PipeServer { + bool started; + Service service; + NamedPipeAcceptor acceptor; + SECURITY_ATTRIBUTES securityAttributes; + void * userData; + OnConnected onConnected; + OnError onError; + OnClientMessage onClientMessage; + OnClientError onClientError; + + PipeServer(bool); + ~PipeServer(); + void AcceptNext(); + void Start(TCHAR const * name); + void Stop(); + void ScheduleRead(PipeConnection * connection); +}; + +struct ClientMessageReadHandler { + PipeConnection * connection; + PipeServer * server; + Message * message; + char * buffer; + enum { + MSGSTATE_HEADER, + MSGSTATE_BODY, + MSGSTATE_DONE + } state; + + ClientMessageReadHandler(ClientMessageReadHandler const & other) + : connection(other.connection) + , server(other.server) + , message(other.message) + , buffer(other.buffer) + , state(other.state) + {} + + ClientMessageReadHandler & operator=(ClientMessageReadHandler o) { + connection = o.connection; + server = o.server; + message = o.message; + buffer = o.buffer; + state = o.state; + return *this; + } + + ClientMessageReadHandler(PipeServer * server, PipeConnection * connection) + : server(server) + , connection(connection) + , message(new (std::nothrow) Message()) + , state(MSGSTATE_HEADER) + { + detail::map_value foo_map; + detail::list_value foo_list; + detail::binary_view foo_bin; + detail::string_view foo_str; + detail::int32_value foo_int32; + detail::int64_value foo_int64; + detail::byte_value foo_byte; + DWORD result = connection->conn.AsyncRead(reinterpret_cast<BYTE*>(message), sizeof(UINT32) * 2, *this); + if(result != NO_ERROR) { + server->onClientError(connection, result, server->userData); + } + } + + void operator()(DWORD err, DWORD bytes) { + if(state == MSGSTATE_HEADER) { + OnHeaderReceived(err, bytes); + } + else if(state == MSGSTATE_BODY) { + OnBodyReceived(err, bytes); + } + } + + bool ReadSize(char const *& buffer, UINT32 & bytesLeft, UINT32 & target) { + if(bytesLeft < sizeof(UINT32)) { + return false; + } + bytesLeft -= sizeof(UINT32); + target = *reinterpret_cast<UINT32 const*>(buffer); + buffer += sizeof(UINT32); + return true; + } + + bool ReadString(char const *& buffer, UINT32 length, UINT32 & bytesLeft, char const *& target, std::vector<std::string> & store) { + if(bytesLeft < length) { + return false; + } + bytesLeft -= length; + store.push_back(std::string(buffer, buffer + length)); + buffer += length; + target = store.back().c_str(); + return true; + } + + bool ReadEntry(char const *& buffer, UINT32 & bytesLeft, MessageEntry & entry, std::vector<std::string> & store) { + if(ReadSize(buffer, bytesLeft, entry.Length)) { + if(ReadString(buffer, entry.Length, bytesLeft, entry.Value, store)) { + return true; + } + } + return false; + } + + void OnBodyReceived(DWORD err, DWORD bytes) { + if(err != NO_ERROR) { + if(server->onClientError) { + server->onClientError(connection, err, server->userData); + } + } + else if(bytes != message->BodySize) { + // We're still missing data, reschedule read + } + else { + state = MSGSTATE_DONE; + buffer[message->BodySize-1] = 0; // Enforce 0 termination + + std::vector<MessageField> fieldStore(message->FieldCount); + std::vector<std::string> stringStore; + stringStore.reserve(message->FieldCount * 2); + char const * ptr = buffer; + UINT32 bytesLeft = bytes; + for(size_t i = 0; i < fieldStore.size(); ++i) { + if(!ReadEntry(ptr, bytesLeft, fieldStore[i].Key, stringStore)) { + break; + } + if(!ReadEntry(ptr, bytesLeft, fieldStore[i].Value, stringStore)) { + break; + } + } + message->Fields = &fieldStore[0]; + server->onClientMessage(connection, message, server->userData); + server->ScheduleRead(connection); + } + delete[] buffer; + delete message; + } + + void OnHeaderReceived(DWORD err, DWORD bytes) { + if(err != NO_ERROR) { + // handle error + if(server->onClientError) { + server->onClientError(connection, err, server->userData); + } + } + else if(bytes != (sizeof(UINT32) * 2)) { + // We're still missing data, reschedule read + } + else { + buffer = new (std::nothrow) char[message->BodySize](); + state = MSGSTATE_BODY; + connection->conn.AsyncRead(reinterpret_cast<BYTE*>(buffer), message->BodySize, *this); + } + } +}; + +AcceptResultHandler::AcceptResultHandler(PipeServer * server, PipeConnection * connection) +: server(server) +, connection(connection) +{} + +void AcceptResultHandler::operator ()(DWORD err, DWORD trans) +{ + if(err != 0) { + if(server->onError) { + server->onError(server, HRESULT_FROM_WIN32(err), server->userData); + } + } + else { + ULONG pid = 0; + ::GetNamedPipeClientProcessId(connection->conn.Native(), &pid); + server->onConnected(server, connection, pid, server->userData); + server->ScheduleRead(connection); + } + server->AcceptNext(); +} + +PipeServer::PipeServer(bool start) +: started(start) +, service() +, acceptor(service) +, securityAttributes() +{ +} + +PipeServer::~PipeServer() { + Stop(); + service.Stop(); +} + +void PipeServer::AcceptNext() { + PipeConnection * client = new PipeConnection(this); + HRESULT result = S_OK; + if(FAILED(result = HRESULT_FROM_WIN32(acceptor.AsyncAccept(client->conn, AcceptResultHandler(this, client))))) { + if(onError) { + onError(this, result, userData); + } + } +} + +void PipeServer::Start(TCHAR const * name) { + InitializeSecurityAttribute(&securityAttributes); + HRESULT result = S_OK; + if(FAILED(result = HRESULT_FROM_WIN32(acceptor.Open(name, &securityAttributes)))) { + if(onError) { + onError(this, result, userData); + } + } + else { + this->AcceptNext(); + } + if(started) service.Start(); + else service.Run(); +} + +void PipeServer::Stop() { + service.Stop(); + acceptor.Close(); +} + +void PipeServer::ScheduleRead(PipeConnection * connection) { + ClientMessageReadHandler(this, connection); +} + +PipeConnection::PipeConnection(PipeServer * server) +: conn(server->service) +, server(server) +{} + +void PipeConnection::Close(){ + conn.Close(); +} + + +extern "C" { + PipeServer * PipeServer_NewWithThread( + void * userData, + OnConnected onConnected, + OnError onError, + OnClientMessage onClientMessage, + OnClientError onClientError) { + + PipeServer * self = new (std::nothrow) PipeServer(true); + if(self) { + self->onClientError = onClientError; + self->onClientMessage = onClientMessage; + self->onConnected = onConnected; + self->onError = onError; + self->userData = userData; + } + return self; + } + + PipeServer * PipeServer_New( + void * userData, + OnConnected onConnected, + OnError onError, + OnClientMessage onClientMessage, + OnClientError onClientError) { + + PipeServer * self = new (std::nothrow) PipeServer(false); + if(self) { + self->onClientError = onClientError; + self->onClientMessage = onClientMessage; + self->onConnected = onConnected; + self->onError = onError; + self->userData = userData; + } + return self; + } + + void PipeServer_Start(PipeServer * self, TCHAR const * name) { + self->Start(name); + } + + void PipeServer_Stop(PipeServer * self) { + self->Stop(); + } + + void PipeServer_Free(PipeServer * self) { + delete self; + } + + INT32 PipeConnection_Send( + PipeConnection * connection, + Message * message, + void *userData, + OnMessageCompleted onCompletion) { + if(!message) { + return ERROR_INVALID_PARAMETER; + } + ClientSendHandler handler(connection, message, userData, onCompletion); + connection->conn.AsyncWrite(handler.buffer(), handler.bufferLength(), handler); + return 0; + } + + void PipeConnection_Close(PipeConnection * self) { + self->Close(); + } + + void PipeConnection_Free(PipeConnection * self) { + delete self; + } +}; diff --git a/tray/win32/ovirt-tray/pipeserver/pipeserver.h b/tray/win32/ovirt-tray/pipeserver/pipeserver.h new file mode 100644 index 0000000..f95326d --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/pipeserver.h @@ -0,0 +1,54 @@ +#include <windows.h> +#include <Sddl.h> +#include <string> +#include <vector> +#include <process.h> +#include "message.h" +#ifdef PIPESERVER_EXPORTS +#define PIPESERVER_API __declspec(dllexport) +#else +#define PIPESERVER_API __declspec(dllimport) +#endif + +inline void InitializeSecurityAttribute(LPSECURITY_ATTRIBUTES sa) { + sa->nLength = sizeof(*sa); + sa->bInheritHandle = FALSE; + ConvertStringSecurityDescriptorToSecurityDescriptor( + TEXT("S:(ML;;NW;;;LW)D:(A;;0x12019f;;;WD)"), + SDDL_REVISION_1, &sa->lpSecurityDescriptor, 0); +} + +struct PipeServer; +struct PipeConnection; +extern "C" { + typedef void (*OnConnected)(PipeServer*, PipeConnection *, DWORD, void *); + typedef void (*OnClientMessage)(PipeConnection *, Message*, void *); + typedef void (*OnClientError)(PipeConnection *, INT32, void *); + typedef void (*OnError)(PipeServer *, INT32, void *); + typedef void (*OnMessageCompleted)(PipeConnection *, UINT32, INT32, void *); + + PIPESERVER_API PipeServer * PipeServer_NewWithThread( + void * userData, + OnConnected onConnected, + OnError onError, + OnClientMessage onClientMessage, + OnClientError onClientError); + PIPESERVER_API PipeServer * PipeServer_New( + void * userData, + OnConnected onConnected, + OnError onError, + OnClientMessage onClientMessage, + OnClientError onClientError); + PIPESERVER_API void PipeServer_Start(PipeServer *, TCHAR const * name); + PIPESERVER_API void PipeServer_Stop(PipeServer *); + PIPESERVER_API void PipeServer_Free(PipeServer *); + + PIPESERVER_API INT32 PipeConnection_Send( + PipeConnection * connection, + Message * message, + void *userData, + OnMessageCompleted onCompletion); + + PIPESERVER_API void PipeConnection_Close(PipeConnection *); + PIPESERVER_API void PipeConnection_Free(PipeConnection *); +}; \ No newline at end of file diff --git a/tray/win32/ovirt-tray/pipeserver/pipeserver.vcproj b/tray/win32/ovirt-tray/pipeserver/pipeserver.vcproj new file mode 100644 index 0000000..44ae4aa --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/pipeserver.vcproj @@ -0,0 +1,487 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="pipeserver" + ProjectGUID="{A87356ED-7C0B-42CA-9327-E7CDE9C4E481}" + RootNamespace="pipeserver" + Keyword="Win32Proj" + TargetFrameworkVersion="196613" + > + <Platforms> + <Platform + Name="Win32" + /> + <Platform + Name="x64" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="2" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PIPESERVER_EXPORTS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="2" + WarningLevel="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="2" + GenerateDebugInformation="true" + SubSystem="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="2" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + EnableIntrinsicFunctions="true" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;PIPESERVER_EXPORTS" + RuntimeLibrary="0" + EnableFunctionLevelLinking="true" + UsePrecompiledHeader="2" + WarningLevel="3" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="1" + GenerateDebugInformation="true" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|x64" + OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" + ConfigurationType="2" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PIPESERVER_EXPORTS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="2" + WarningLevel="3" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="2" + GenerateDebugInformation="true" + SubSystem="2" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" + ConfigurationType="2" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + EnableIntrinsicFunctions="true" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;PIPESERVER_EXPORTS" + RuntimeLibrary="0" + EnableFunctionLevelLinking="true" + UsePrecompiledHeader="2" + WarningLevel="3" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="1" + GenerateDebugInformation="true" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath=".\dllmain.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0" + CompileAsManaged="0" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0" + CompileAsManaged="0" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug|x64" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0" + CompileAsManaged="0" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|x64" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0" + CompileAsManaged="0" + /> + </FileConfiguration> + </File> + <File + RelativePath=".\pipeserver.cpp" + > + </File> + <File + RelativePath=".\stdafx.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="1" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="1" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug|x64" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="1" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|x64" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="1" + /> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath=".\bson.h" + > + </File> + <File + RelativePath=".\critical_section.h" + > + </File> + <File + RelativePath=".\function_storage.h" + > + </File> + <File + RelativePath=".\handle.h" + > + </File> + <File + RelativePath=".\handler_functions.h" + > + </File> + <File + RelativePath=".\handler_impl.h" + > + </File> + <File + RelativePath=".\iofunoverlapped.h" + > + </File> + <File + RelativePath=".\message.h" + > + </File> + <File + RelativePath=".\named_pipe.h" + > + </File> + <File + RelativePath=".\pipeserver.h" + > + </File> + <File + RelativePath=".\ref_ptr.h" + > + </File> + <File + RelativePath=".\service.h" + > + </File> + <File + RelativePath=".\stdafx.h" + > + </File> + <File + RelativePath=".\stream_service.h" + > + </File> + <File + RelativePath=".\targetver.h" + > + </File> + <File + RelativePath=".\utilities.h" + > + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + <File + RelativePath=".\ReadMe.txt" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/tray/win32/ovirt-tray/pipeserver/ref_ptr.h b/tray/win32/ovirt-tray/pipeserver/ref_ptr.h new file mode 100644 index 0000000..be31db7 --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/ref_ptr.h @@ -0,0 +1,107 @@ +#pragma once + +template <class T> +class ref_ptr { +public: + typedef T type; + + template< typename U > + explicit ref_ptr(U * u) + : ptr_(u) + , refs_(new long(1)) + {} + + explicit ref_ptr(T * u) + : ptr_(u) + , refs_(new long(1)) + {} + + ref_ptr() + : ptr_() + , refs_() + {} + + template< typename U > + ref_ptr(ref_ptr<U> const & other) + : ptr_(other.ptr_) + , refs_(other.refs_) + { + ++*refs_; + } + + + explicit ref_ptr(ref_ptr const & p) throw() + : ptr_(p.ptr_) + , refs_(p.refs_) + { + ++*refs_; + } + + ~ref_ptr () { + release(); + } + + void swap(ref_ptr & other) { + std::swap(other.ptr_, ptr_); + std::swap(other.refs_, refs_); + } + + ref_ptr & operator= (ref_ptr p) { + swap(p); + return *this; + } + + ref_ptr & operator=(T * p) { + ref_ptr tmp(p); + swap(tmp); + return *this; + } + + template< typename U > + ref_ptr & operator=(U * p) { + ref_ptr tmp(p); + swap(tmp); + return *this; + } + + template< typename U > + ref_ptr & operator=(ref_ptr<U> const & p) { + ref_ptr<T> tmp = p; + swap(tmp); + return *this; + } + + T * get() const { + return ptr_; + } + + template< typename U > + U * dynamic_as() const { + return dynamic_cast<U*>(get()) + } + + template< typename U > + U * static_as() const { + return static_cast<U*>(get()) + } + + T& operator*() const { + return *get(); + } + T* operator->() const { + return get(); + } + +private: + void release() { + if (--*refs_ == 0) { + delete refs_; + delete ptr_; + } + } + +protected: + T* ptr_; + long * refs_; + +}; diff --git a/tray/win32/ovirt-tray/pipeserver/service.h b/tray/win32/ovirt-tray/pipeserver/service.h new file mode 100644 index 0000000..76cafbd --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/service.h @@ -0,0 +1,110 @@ +#pragma once + +#include <windows.h> +#include <process.h> + +#include <vector> +#include "utilities.h" +#include "iofunoverlapped.h" + +struct CompletionWrapper { + CompletionWrapper(CompletionHandler callable) + : Callable(callable) + {} + + void operator()(DWORD, DWORD) { + if(Callable) Callable(); + } + + CompletionHandler Callable; +}; + +enum { + OVERLAPPED_CONTAINS_RESULT = 1, +}; + +struct Service { + + Service() + : port_(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0)) + { + } + + ~Service() + { + Stop(); + } + + void Start() { + threads_.push_back((HANDLE) _beginthread(&Service::Run_, 0, this)); + } + + void Run() { + threads_.push_back(GetCurrentThread()); + RunInternal(); + } + + void Stop() { + if (!threads_.empty()) { + for (std::size_t i = 0; i < threads_.size(); ++i) { + ::PostQueuedCompletionStatus(port_, 0, 0, 0); + } + ::WaitForMultipleObjects(DWORD(threads_.size()), &threads_[0], TRUE, INFINITE); + threads_.clear(); + } + } + + DWORD PostCompletionStatus(DWORD err, DWORD trans, OVERLAPPED * overlapped) { + if (!::PostQueuedCompletionStatus(port_, err, trans, overlapped)) { + return GetLastError(); + } + return NO_ERROR; + } + + DWORD Post(CompletionHandler f) { + if (::PostQueuedCompletionStatus(port_, 0, 0, new IOFunOverlapped(CompletionWrapper(f)))) { + return NO_ERROR; + } + return GetLastError(); + } + + bool Register(Handle & h) { + return ::CreateIoCompletionPort(h, port_, 0, 0) == port_; + } +protected: + void RunInternal() { + DWORD transferred = 0; + ULONG_PTR key = 0; + LPOVERLAPPED overlapped = 0; + for(;;) { + BOOL getResult = ::GetQueuedCompletionStatus(port_, &transferred, &key, &overlapped, INFINITE); + if (getResult) { + if (key == 0 && transferred == 0 && overlapped == 0) { + break; + } + } + if (overlapped) { + DWORD last_error = GetLastError(); + if (!getResult) { + overlapped->Internal = last_error; + overlapped->InternalHigh = transferred; + } + else { + last_error = NO_ERROR; + } + reinterpret_cast<IOFunOverlapped*>(overlapped)->Perform(last_error, transferred); + reinterpret_cast<IOFunOverlapped*>(overlapped)->Release(); + } + } + } + + static void Run_(void * p) { + reinterpret_cast<Service*>(p)->RunInternal(); + } +private: + Service(Service const &); + Service & operator=(Service const &); +private: + std::vector<HANDLE> threads_; + Handle port_; +}; \ No newline at end of file diff --git a/tray/win32/ovirt-tray/pipeserver/stdafx.cpp b/tray/win32/ovirt-tray/pipeserver/stdafx.cpp new file mode 100644 index 0000000..5fcf8f2 --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// pipeserver.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/tray/win32/ovirt-tray/pipeserver/stdafx.h b/tray/win32/ovirt-tray/pipeserver/stdafx.h new file mode 100644 index 0000000..f3a0737 --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/stdafx.h @@ -0,0 +1,16 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include <windows.h> + + + +// TODO: reference additional headers your program requires here diff --git a/tray/win32/ovirt-tray/pipeserver/stream_service.h b/tray/win32/ovirt-tray/pipeserver/stream_service.h new file mode 100644 index 0000000..7026ce3 --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/stream_service.h @@ -0,0 +1,136 @@ +#pragma once + +#include "service.h" +#include "iofunoverlapped.h" + + +struct StreamService { + StreamService(Service & s) + : service_(s) + {} + + bool Register(Handle & h) { + return service_.Register(h); + } + + DWORD Open(Handle & h, TCHAR const * path) { + h = ::CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if (!h) { + return GetLastError(); + } + if (!service_.Register(h)) { + return GetLastError(); + } + return NO_ERROR; + } + + void Close(Handle & h) { + h.Close(); + } + + void Cancel(Handle & h) { + ::CancelIoEx(h, 0); + } + + DWORD AsyncRead(Handle & h, BYTE * buffer, DWORD buffer_size, IOHandler completion) { + + IOFunOverlapped * trans = new IOFunOverlapped(completion); + DWORD transferred = 0; + trans->AddRef(); + if (!::ReadFile(h, buffer, buffer_size, &transferred, trans)) { + if (GetLastError() != ERROR_IO_PENDING) { + // On an error we have to release both references + trans->Release(); + trans->Release(); + return GetLastError(); + } + } + else { + trans->AddRef(); + service_.PostCompletionStatus(NO_ERROR, transferred, trans); + } + trans->Release(); + return ERROR_SUCCESS; + } + + DWORD AsyncWrite(Handle & h, BYTE const * buffer, DWORD buffer_size, IOHandler completion) { + IOFunOverlapped * trans = new IOFunOverlapped(completion); + DWORD transferred = 0; + trans->AddRef(); + if (!::WriteFile(h, buffer, buffer_size, &transferred, trans)) { + if (GetLastError() != ERROR_IO_PENDING) { + // On an error we have to release both references + trans->Release(); + trans->Release(); + return GetLastError(); + } + } + else { + trans->AddRef(); + service_.PostCompletionStatus(NO_ERROR, transferred, trans); + } + trans->Release(); + return ERROR_SUCCESS; + } + +protected: + Service & service_; +}; + +template< typename StreamServiceT = StreamService > +struct BasicStream { + BasicStream(Service & s) + : handle_(INVALID_HANDLE_VALUE) + , service_(s) + , stream_service_(s) + {} + + void Swap(BasicStream & other) { + std::swap(handle_, other.handle_); + } + + DWORD Open(TCHAR const * path) { + Close(); + return stream_service_.Open(Native(), path); + } + + void Assign(Handle & h) { + Close(); + handle_ = h; + } + + Handle & Native() { + return handle_; + } + + void Cancel() { + stream_service_.Cancel(handle_); + } + + void Close() { + stream_service_.Close(handle_); + } + + bool IsOpen() const { + return handle_; + } + + Service & GetService() { + return service_; + } + + DWORD AsyncRead(BYTE * buffer, DWORD buffer_size, IOHandler completion) { + return stream_service_.AsyncRead(handle_, buffer, buffer_size, completion); + } + + DWORD AsyncWrite(BYTE const * buffer, DWORD buffer_size, IOHandler completion) { + return stream_service_.AsyncWrite(handle_, buffer, buffer_size, completion); + } + +protected: + Handle handle_; + Service & service_; + StreamServiceT stream_service_; +}; + +typedef BasicStream<> Stream; diff --git a/tray/win32/ovirt-tray/pipeserver/targetver.h b/tray/win32/ovirt-tray/pipeserver/targetver.h new file mode 100644 index 0000000..c83c946 --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/targetver.h @@ -0,0 +1,24 @@ +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Specifies that the minimum required platform is Windows Vista. +#define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98. +#define _WIN32_WINDOWS 0x0501 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. +#define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE. +#endif diff --git a/tray/win32/ovirt-tray/pipeserver/utilities.h b/tray/win32/ovirt-tray/pipeserver/utilities.h new file mode 100644 index 0000000..5f5844e --- /dev/null +++ b/tray/win32/ovirt-tray/pipeserver/utilities.h @@ -0,0 +1,9 @@ +#pragma once + +#include <windows.h> + +inline DWORD GetPlatformThreadCount() { + SYSTEM_INFO info = {}; + ::GetNativeSystemInfo(&info); + return info.dwNumberOfProcessors; +} -- To view, visit http://gerrit.ovirt.org/34443 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I3c0caa72b548bb3ce39e06f7dc879709dba89989 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-guest-agent Gerrit-Branch: master Gerrit-Owner: Vinzenz Feenstra <vfeen...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches