[Spice-commits] 6 commits - common/vdcommon.h vdagent/pci_vdi_port.cpp vdagent/pci_vdi_port.h vdagent/vdagent.cpp vdagent/vdagent.vcproj vdagent/vdi_port.cpp vdagent/vdi_port.h vdagent/virtio_vdi_port.cpp vdagent/virtio_vdi_port.h vdservice/pci_vdi_port.cpp vdservice/pci_vdi_port.h vdservice/vdi_port.cpp vdservice/vdi_port.h vdservice/vdservice.cpp vdservice/vdservice.vcproj vdservice/virtio_vdi_port.cpp vdservice/virtio_vdi_port.h

Arnon Gilboa agilboa at kemper.freedesktop.org
Wed Nov 14 00:51:39 PST 2012


 common/vdcommon.h             |   31 --
 vdagent/pci_vdi_port.cpp      |  132 +++++++++
 vdagent/pci_vdi_port.h        |   59 ++++
 vdagent/vdagent.cpp           |  555 ++++++++++++++++++++----------------------
 vdagent/vdagent.vcproj        |   32 ++
 vdagent/vdi_port.cpp          |   90 ++++++
 vdagent/vdi_port.h            |   75 +++++
 vdagent/virtio_vdi_port.cpp   |  187 ++++++++++++++
 vdagent/virtio_vdi_port.h     |   33 ++
 vdservice/pci_vdi_port.cpp    |  132 ---------
 vdservice/pci_vdi_port.h      |   59 ----
 vdservice/vdi_port.cpp        |   90 ------
 vdservice/vdi_port.h          |   75 -----
 vdservice/vdservice.cpp       |  471 ++---------------------------------
 vdservice/vdservice.vcproj    |   24 -
 vdservice/virtio_vdi_port.cpp |  187 --------------
 vdservice/virtio_vdi_port.h   |   33 --
 17 files changed, 916 insertions(+), 1349 deletions(-)

New commits:
commit a69af07da34b3206f8354ac3879177483d5956ce
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Wed Nov 7 14:38:20 2012 +0200

    vdagent: set timeout for next clipboard chunk instead of complete reception
    
    currently:
    -handling client disconnect during clipboard data trasfer is buggy
    -agent also timeouts on large paste from client (>10sec)
    
    therfore:
    -reduce VD_CLIPBOARD_TIMEOUT_MS to 3sec from previous clipboard chunk
    -remove _clipboard_event and use _control_event(CONTROL_CLIPBOARD) instead
    -use _clipboard_tick for clipboard timeout, updated on each clipboard chunk
    -use cleanup_in_msg() to reset incoming message state
    
    rhbz#833835

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index 7495826..9537b90 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -32,7 +32,7 @@
 #define VD_AGENT_WINCLASS_NAME  TEXT("VDAGENT")
 #define VD_INPUT_INTERVAL_MS    20
 #define VD_TIMER_ID             1
-#define VD_CLIPBOARD_TIMEOUT_MS 10000
+#define VD_CLIPBOARD_TIMEOUT_MS 3000
 #define VD_CLIPBOARD_FORMAT_MAX_TYPES 16
 
 //FIXME: extract format/type stuff to win_vdagent_common for use by windows\platform.cpp as well
@@ -107,7 +107,7 @@ private:
     DWORD get_cximage_format(uint32_t type);
     enum { owner_none, owner_guest, owner_client };
     void set_clipboard_owner(int new_owner);
-    enum { CONTROL_STOP, CONTROL_DESKTOP_SWITCH, CONTROL_LOGON };
+    enum { CONTROL_STOP, CONTROL_DESKTOP_SWITCH, CONTROL_LOGON, CONTROL_CLIPBOARD };
     void set_control_event(int control_command);
     void handle_control_event();
     VDIChunk* new_chunk(DWORD bytes = 0);
@@ -119,6 +119,7 @@ private:
     void set_display_depth(uint32_t depth);
     void load_display_setting();
     bool send_announce_capabilities(bool request);
+    void cleanup_in_msg();
     void cleanup();
 
 private:
@@ -126,13 +127,13 @@ private:
     HWND _hwnd;
     HWND _hwnd_next_viewer;
     int _clipboard_owner;
+    DWORD _clipboard_tick;
     DWORD _buttons_state;
     ULONG _mouse_x;
     ULONG _mouse_y;
     INPUT _input;
     DWORD _input_time;
     HANDLE _control_event;
-    HANDLE _clipboard_event;
     HANDLE* _events;
     VDAgentMessage* _in_msg;
     uint32_t _in_msg_pos;
@@ -174,12 +175,12 @@ VDAgent::VDAgent()
     : _hwnd (NULL)
     , _hwnd_next_viewer (NULL)
     , _clipboard_owner (owner_none)
+    , _clipboard_tick (0)
     , _buttons_state (0)
     , _mouse_x (0)
     , _mouse_y (0)
     , _input_time (0)
     , _control_event (NULL)
-    , _clipboard_event (NULL)
     , _events (NULL)
     , _in_msg (NULL)
     , _in_msg_pos (0)
@@ -259,8 +260,7 @@ bool VDAgent::run()
         vd_printf("SetProcessShutdownParameters failed %lu", GetLastError());
     }
     _control_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-    _clipboard_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (!_control_event || !_clipboard_event) {
+    if (!_control_event) {
         vd_printf("CreateEvent() failed: %lu", GetLastError());
         cleanup();
         return false;
@@ -313,7 +313,6 @@ bool VDAgent::run()
 void VDAgent::cleanup()
 {
     CloseHandle(_control_event);
-    CloseHandle(_clipboard_event);
     delete _vdi_port;
     delete _desktop_layout;
 }
@@ -353,6 +352,9 @@ void VDAgent::handle_control_event()
                 _logon_occured = true;
             }
             break;
+        case CONTROL_CLIPBOARD:
+            _clipboard_tick = 0;
+            break;
         default:
             vd_printf("Unsupported control command %u", control_command);
         }
@@ -641,11 +643,11 @@ bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
 
     if (_clipboard_owner != owner_client) {
         vd_printf("Received clipboard data from client while clipboard is not owned by client");
-        SetEvent(_clipboard_event);
+        set_control_event(CONTROL_CLIPBOARD);
         return false;
     }
     if (clipboard->type == VD_AGENT_CLIPBOARD_NONE) {
-        SetEvent(_clipboard_event);
+        set_control_event(CONTROL_CLIPBOARD);
         return false;
     }
     switch (clipboard->type) {
@@ -666,7 +668,7 @@ bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
     }
     format = get_clipboard_format(clipboard->type);
     if (SetClipboardData(format, clip_data)) {
-        SetEvent(_clipboard_event);
+        set_control_event(CONTROL_CLIPBOARD);
         return true;
     }
     // We retry clipboard open-empty-set-close only when there is a timeout in on_clipboard_request()
@@ -942,26 +944,16 @@ void VDAgent::on_clipboard_request(UINT format)
         return;
     }
 
-    // next clipboard event will be considered a reply to this request
-    ResetEvent(_clipboard_event);
-
-    DWORD start_tick = GetTickCount();
-    do {
-        DWORD wait_result = WaitForSingleObjectEx(_clipboard_event, 1000, TRUE);
-
-        switch (wait_result) {
-        case WAIT_OBJECT_0:
-            return;
-        case WAIT_IO_COMPLETION:
-        case WAIT_TIMEOUT:
-            break;
-        default:
-            vd_printf("Wait error (%lu)\n", GetLastError());
-            return;
-        }
-    } while (GetTickCount() < start_tick + VD_CLIPBOARD_TIMEOUT_MS);
+    _clipboard_tick = GetTickCount();
+    while (_running && _clipboard_tick &&
+           GetTickCount() < _clipboard_tick + VD_CLIPBOARD_TIMEOUT_MS) {
+        event_dispatcher(VD_CLIPBOARD_TIMEOUT_MS, 0);
+    }
 
-    vd_printf("wait timeout.. ");
+    cleanup_in_msg();
+    if (_clipboard_tick) {
+        vd_printf("Clipboard wait timeout");
+    }
 }
 
 void VDAgent::on_clipboard_release()
@@ -1096,7 +1088,7 @@ void VDAgent::handle_clipboard_release()
         vd_printf("Received clipboard release from client while clipboard is not owned by client");
         return;
     }
-    SetEvent(_clipboard_event);
+    set_control_event(CONTROL_CLIPBOARD);
     set_clipboard_owner(owner_none);
 }
 
@@ -1277,15 +1269,24 @@ void VDAgent::handle_chunk(VDIChunk* chunk)
     } else {
         memcpy((uint8_t*)_in_msg + _in_msg_pos, chunk->data, chunk->hdr.size);
         _in_msg_pos += chunk->hdr.size;
+        // update clipboard tick on each clipboard chunk for timeout setting
+        if (_in_msg->type == VD_AGENT_CLIPBOARD) {
+            _clipboard_tick = GetTickCount();
+        }
         if (_in_msg_pos == sizeof(VDAgentMessage) + _in_msg->size) {
             dispatch_message(_in_msg, 0);
-            _in_msg_pos = 0;
-            delete[] (uint8_t *)_in_msg;
-            _in_msg = NULL;
+            cleanup_in_msg();
         }
     }
 }
 
+void VDAgent::cleanup_in_msg()
+{
+    _in_msg_pos = 0;
+    delete[] (uint8_t *)_in_msg;
+    _in_msg = NULL;
+}
+
 void VDAgent::handle_port_out()
 {
     MUTEX_LOCK(_message_mutex);
commit f71197330c7e11b0956e598a4d571f388b9dc088
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Wed Nov 7 14:28:27 2012 +0200

    vdagent: extract event_dispatcher from input_desktop_message_loop

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index 9bb0898..7495826 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -80,6 +80,7 @@ public:
 private:
     VDAgent();
     void input_desktop_message_loop();
+    void event_dispatcher(DWORD timeout, DWORD wake_mask);
     bool handle_mouse_event(VDAgentMouseState* state);
     bool handle_announce_capabilities(VDAgentAnnounceCapabilities* announce_capabilities,
                                       uint32_t msg_size);
@@ -362,9 +363,7 @@ void VDAgent::handle_control_event()
 void VDAgent::input_desktop_message_loop()
 {
     TCHAR desktop_name[MAX_PATH];
-    DWORD wait_ret;
     HDESK hdesk;
-    MSG msg;
 
     hdesk = OpenInputDesktop(0, FALSE, GENERIC_ALL);
     if (!hdesk) {
@@ -412,53 +411,7 @@ void VDAgent::input_desktop_message_loop()
     }
     _hwnd_next_viewer = SetClipboardViewer(_hwnd);
     while (_running && !_desktop_switch) {
-        int cont_read = _vdi_port->read();
-        int cont_write = _vdi_port->write();
-        bool cont = false;
-
-        if (cont_read >= 0 && cont_write >= 0) {
-            cont = cont_read || cont_write;
-        } else if (cont_read == VDI_PORT_ERROR || cont_write == VDI_PORT_ERROR) {
-            vd_printf("VDI Port error, read %d write %d", cont_read, cont_write);
-            _running = false;
-            break;
-        } else if (cont_read == VDI_PORT_RESET || cont_write == VDI_PORT_RESET) {
-            vd_printf("VDI Port reset, read %d write %d", cont_read, cont_write);
-            _running = false;
-            break;
-        }
-        if (cont_read) {
-            handle_port_in();
-        }
-        if (cont_write) {
-            handle_port_out();
-        }
-
-        wait_ret = MsgWaitForMultipleObjectsEx(_events_count, _events, cont ? 0 : INFINITE,
-                                               QS_ALLINPUT, MWMO_ALERTABLE);
-        if (wait_ret == WAIT_OBJECT_0 + _events_count) {
-            while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
-                TranslateMessage(&msg);
-                DispatchMessage(&msg);
-            }
-            continue;
-        }
-        switch (wait_ret) {
-        case WAIT_OBJECT_0 + VD_EVENT_CONTROL:
-            handle_control_event();
-            break;
-        case WAIT_IO_COMPLETION:
-        case WAIT_TIMEOUT:
-            break;
-        default:
-            DWORD vdi_event = wait_ret - VD_STATIC_EVENTS_COUNT - WAIT_OBJECT_0;
-            if (vdi_event >= 0 && vdi_event < _vdi_port->get_num_events()) {
-                _running = _vdi_port->handle_event(vdi_event);
-            } else {
-                vd_printf("MsgWaitForMultipleObjectsEx failed: %lu %lu", wait_ret, GetLastError());
-                _running = false;
-            }
-        }
+        event_dispatcher(INFINITE, QS_ALLINPUT);
     }
     _desktop_switch = false;
     if (_pending_input) {
@@ -471,6 +424,60 @@ void VDAgent::input_desktop_message_loop()
     CloseDesktop(hdesk);
 }
 
+void VDAgent::event_dispatcher(DWORD timeout, DWORD wake_mask)
+{
+    DWORD wait_ret;
+    MSG msg;
+
+    int cont_read = _vdi_port->read();
+    int cont_write = _vdi_port->write();
+    bool cont = false;
+
+    if (cont_read >= 0 && cont_write >= 0) {
+        cont = cont_read || cont_write;
+    } else if (cont_read == VDI_PORT_ERROR || cont_write == VDI_PORT_ERROR) {
+        vd_printf("VDI Port error, read %d write %d", cont_read, cont_write);
+        _running = false;
+        return;
+    } else if (cont_read == VDI_PORT_RESET || cont_write == VDI_PORT_RESET) {
+        vd_printf("VDI Port reset, read %d write %d", cont_read, cont_write);
+        _running = false;
+        return;
+    }
+    if (cont_read) {
+        handle_port_in();
+    }
+    if (cont_write) {
+        handle_port_out();
+    }
+
+    wait_ret = MsgWaitForMultipleObjects(_events_count, _events, FALSE, cont ? 0 : timeout,
+                                         wake_mask);
+
+    if (wake_mask && wait_ret == WAIT_OBJECT_0 + _events_count) {
+        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+            TranslateMessage(&msg);
+            DispatchMessage(&msg);
+        }
+        return;
+    }
+    switch (wait_ret) {
+    case WAIT_OBJECT_0 + VD_EVENT_CONTROL:
+        handle_control_event();
+        break;
+    case WAIT_TIMEOUT:
+        break;
+    default:
+        DWORD vdi_event = wait_ret - VD_STATIC_EVENTS_COUNT - WAIT_OBJECT_0;
+        if (vdi_event >= 0 && vdi_event < _vdi_port->get_num_events()) {
+            _running = _vdi_port->handle_event(vdi_event);
+        } else {
+            vd_printf("MsgWaitForMultipleObjectsEx failed: %lu %lu", wait_ret, GetLastError());
+            _running = false;
+        }
+    }
+}
+
 DWORD VDAgent::get_buttons_change(DWORD last_buttons_state, DWORD new_buttons_state,
                                   DWORD mask, DWORD down_flag, DWORD up_flag)
 {
commit 5f1e7630ae7ea11dc6e95a8bd57a4396dfd69428
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Tue Nov 6 12:37:15 2012 +0200

    vdagent: remove pipe common defs

diff --git a/common/vdcommon.h b/common/vdcommon.h
index 394333b..e50f2b0 100644
--- a/common/vdcommon.h
+++ b/common/vdcommon.h
@@ -32,19 +32,8 @@ typedef CRITICAL_SECTION mutex_t;
 #define MUTEX_LOCK(mutex) EnterCriticalSection(&mutex)
 #define MUTEX_UNLOCK(mutex) LeaveCriticalSection(&mutex)
 
-#define VD_SERVICE_PIPE_NAME   TEXT("\\\\.\\pipe\\vdservicepipe")
-#define VD_MESSAGE_HEADER_SIZE (sizeof(VDPipeMessage) + sizeof(VDAgentMessage))
-#define VD_PIPE_BUF_SIZE       (1024 * 1024)
 #define VD_AGENT_REGISTRY_KEY "SOFTWARE\\Red Hat\\Spice\\vdagent\\"
 
-enum {
-    VD_AGENT_COMMAND,
-    VD_AGENT_RESET,
-    VD_AGENT_RESET_ACK,
-    VD_AGENT_QUIT,
-    VD_AGENT_SESSION_LOGON,
-};
-
 #if defined __GNUC__
 #define ALIGN_GCC __attribute__ ((packed))
 #define ALIGN_VC
@@ -57,25 +46,5 @@ enum {
 #define swprintf_s(buf, sz, format...) swprintf(buf, format)
 #endif
 
-typedef struct ALIGN_VC VDPipeMessage {
-    uint32_t type;
-    uint32_t opaque;
-    uint32_t size;
-    uint8_t data[0];
-} ALIGN_GCC VDPipeMessage;
-
-typedef struct VDPipeBuffer {
-    OVERLAPPED overlap;
-    DWORD start;
-    DWORD end;
-    uint8_t data[VD_PIPE_BUF_SIZE];
-} VDPipeBuffer;
-
-typedef struct VDPipeState {
-    HANDLE pipe;
-    VDPipeBuffer write;
-    VDPipeBuffer read;
-} VDPipeState;
-
 #endif
 
commit 22d25256fd25eebb6dea608164d24ed3970e4c31
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Tue Nov 6 12:34:55 2012 +0200

    vdagent: use virtio-serial, remove pipe usage

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index 078e50f..9bb0898 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -16,11 +16,14 @@
 */
 
 #include "vdcommon.h"
+#include "virtio_vdi_port.h"
+#include "pci_vdi_port.h"
 #include "desktop_layout.h"
 #include "display_setting.h"
 #include "ximage.h"
 #undef max
 #undef min
+#include <wtsapi32.h>
 #include <lmcons.h>
 #include <queue>
 #include <set>
@@ -56,6 +59,18 @@ static ImageType image_types[] = {
     {VD_AGENT_CLIPBOARD_IMAGE_BMP, CXIMAGE_FORMAT_BMP},
 };
 
+typedef struct ALIGN_VC VDIChunk {
+    VDIChunkHeader hdr;
+    uint8_t data[0];
+} ALIGN_GCC VDIChunk;
+
+#define VD_MESSAGE_HEADER_SIZE (sizeof(VDIChunk) + sizeof(VDAgentMessage))
+
+enum {
+    VD_EVENT_CONTROL = 0,
+    VD_STATIC_EVENTS_COUNT // Must be last
+};
+
 class VDAgent {
 public:
     static VDAgent* get();
@@ -74,7 +89,9 @@ private:
     bool handle_clipboard_request(VDAgentClipboardRequest* clipboard_request);
     void handle_clipboard_release();
     bool handle_display_config(VDAgentDisplayConfig* display_config, uint32_t port);
-    bool handle_control(VDPipeMessage* msg);
+    void handle_port_in();
+    void handle_port_out();
+    void handle_chunk(VDIChunk* chunk);
     void on_clipboard_grab();
     void on_clipboard_request(UINT format);
     void on_clipboard_release();
@@ -82,8 +99,6 @@ private:
                              DWORD mask, DWORD down_flag, DWORD up_flag);
     static HGLOBAL utf8_alloc(LPCSTR data, int size);
     static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
-    static VOID CALLBACK read_completion(DWORD err, DWORD bytes, LPOVERLAPPED overlap);
-    static VOID CALLBACK write_completion(DWORD err, DWORD bytes, LPOVERLAPPED overlap);
     static DWORD WINAPI event_thread_proc(LPVOID param);
     static void dispatch_message(VDAgentMessage* msg, uint32_t port);
     uint32_t get_clipboard_format(uint32_t type);
@@ -91,14 +106,14 @@ private:
     DWORD get_cximage_format(uint32_t type);
     enum { owner_none, owner_guest, owner_client };
     void set_clipboard_owner(int new_owner);
-    enum { CONTROL_STOP, CONTROL_DESKTOP_SWITCH };
+    enum { CONTROL_STOP, CONTROL_DESKTOP_SWITCH, CONTROL_LOGON };
     void set_control_event(int control_command);
     void handle_control_event();
-    VDPipeMessage* new_message(DWORD bytes = 0);
-    void enqueue_message(VDPipeMessage* msg);
+    VDIChunk* new_chunk(DWORD bytes = 0);
+    void enqueue_chunk(VDIChunk* msg);
     bool write_message(uint32_t type, uint32_t size, void* data);
     bool write_clipboard(VDAgentMessage* msg, uint32_t size);
-    bool connect_pipe();
+    bool init_vdi_port();
     bool send_input();
     void set_display_depth(uint32_t depth);
     void load_display_setting();
@@ -117,20 +132,20 @@ private:
     DWORD _input_time;
     HANDLE _control_event;
     HANDLE _clipboard_event;
+    HANDLE* _events;
     VDAgentMessage* _in_msg;
     uint32_t _in_msg_pos;
+    uint32_t _events_count;
     bool _pending_input;
-    bool _pending_write;
     bool _running;
     bool _desktop_switch;
     DesktopLayout* _desktop_layout;
     DisplaySetting _display_setting;
-    VDPipeState _pipe_state;
-    mutex_t _write_mutex;
+    VDIPort* _vdi_port;
     mutex_t _control_mutex;
     mutex_t _message_mutex;
     std::queue<int> _control_queue;
-    std::queue<VDPipeMessage*> _message_queue;
+    std::queue<VDIChunk*> _message_queue;
 
     bool _logon_desktop;
     bool _display_setting_initialized;
@@ -164,14 +179,16 @@ VDAgent::VDAgent()
     , _input_time (0)
     , _control_event (NULL)
     , _clipboard_event (NULL)
+    , _events (NULL)
     , _in_msg (NULL)
     , _in_msg_pos (0)
+    , _events_count (0)
     , _pending_input (false)
-    , _pending_write (false)
     , _running (false)
     , _desktop_switch (false)
     , _desktop_layout (NULL)
     , _display_setting (VD_AGENT_REGISTRY_KEY)
+    , _vdi_port (NULL)
     , _logon_desktop (false)
     , _display_setting_initialized (false)
     , _client_caps (NULL)
@@ -186,8 +203,6 @@ VDAgent::VDAgent()
         _log = VDLog::get(log_path);
     }
     ZeroMemory(&_input, sizeof(INPUT));
-    ZeroMemory(&_pipe_state, sizeof(VDPipeState));
-    MUTEX_INIT(_write_mutex);
     MUTEX_INIT(_control_mutex);
     MUTEX_INIT(_message_mutex);
 
@@ -196,6 +211,7 @@ VDAgent::VDAgent()
 
 VDAgent::~VDAgent()
 {
+    delete _events;
     delete _log;
     delete[] _client_caps;
 }
@@ -260,7 +276,8 @@ bool VDAgent::run()
     if (_desktop_layout->get_display_count() == 0) {
         vd_printf("No QXL devices!");
     }
-    if (!connect_pipe()) {
+    if (!init_vdi_port()) {
+        vd_printf("Failed to create VDIPort instance");
         cleanup();
         return false;
     }
@@ -272,7 +289,14 @@ bool VDAgent::run()
         return false;
     }
     send_announce_capabilities(true);
-    read_completion(0, 0, &_pipe_state.read.overlap);
+
+    _events_count = VD_STATIC_EVENTS_COUNT + _vdi_port->get_num_events();
+    _events = new HANDLE[_events_count];
+    ZeroMemory(_events, _events_count);
+    _events[VD_EVENT_CONTROL] = _control_event;
+    _vdi_port->fill_events(&_events[VD_STATIC_EVENTS_COUNT]);
+    vd_printf("Connected to server");
+
     while (_running) {
         input_desktop_message_loop();
         if (_clipboard_owner == owner_guest) {
@@ -289,7 +313,7 @@ void VDAgent::cleanup()
 {
     CloseHandle(_control_event);
     CloseHandle(_clipboard_event);
-    CloseHandle(_pipe_state.pipe);
+    delete _vdi_port;
     delete _desktop_layout;
 }
 
@@ -317,6 +341,17 @@ void VDAgent::handle_control_event()
         case CONTROL_DESKTOP_SWITCH:
             _desktop_switch = true;
             break;
+        case CONTROL_LOGON:
+            vd_printf("session logon");
+            // loading the display settings for the current session's logged on user only
+            // after 1) we receive logon event, and 2) the desktop switched from Winlogon
+            if (!_logon_desktop) {
+                vd_printf("LOGON display setting");
+                _display_setting.load();
+            } else {
+                _logon_occured = true;
+            }
+            break;
         default:
             vd_printf("Unsupported control command %u", control_command);
         }
@@ -372,25 +407,57 @@ void VDAgent::input_desktop_message_loop()
         _running = false;
         return;
     }
+    if (!WTSRegisterSessionNotification(_hwnd, NOTIFY_FOR_ALL_SESSIONS)) {
+        vd_printf("WTSRegisterSessionNotification() failed: %lu", GetLastError());
+    }
     _hwnd_next_viewer = SetClipboardViewer(_hwnd);
     while (_running && !_desktop_switch) {
-        wait_ret = MsgWaitForMultipleObjectsEx(1, &_control_event, INFINITE, QS_ALLINPUT,
-                                               MWMO_ALERTABLE);
-        switch (wait_ret) {
-        case WAIT_OBJECT_0:
-            handle_control_event();
+        int cont_read = _vdi_port->read();
+        int cont_write = _vdi_port->write();
+        bool cont = false;
+
+        if (cont_read >= 0 && cont_write >= 0) {
+            cont = cont_read || cont_write;
+        } else if (cont_read == VDI_PORT_ERROR || cont_write == VDI_PORT_ERROR) {
+            vd_printf("VDI Port error, read %d write %d", cont_read, cont_write);
+            _running = false;
             break;
-        case WAIT_OBJECT_0 + 1:
+        } else if (cont_read == VDI_PORT_RESET || cont_write == VDI_PORT_RESET) {
+            vd_printf("VDI Port reset, read %d write %d", cont_read, cont_write);
+            _running = false;
+            break;
+        }
+        if (cont_read) {
+            handle_port_in();
+        }
+        if (cont_write) {
+            handle_port_out();
+        }
+
+        wait_ret = MsgWaitForMultipleObjectsEx(_events_count, _events, cont ? 0 : INFINITE,
+                                               QS_ALLINPUT, MWMO_ALERTABLE);
+        if (wait_ret == WAIT_OBJECT_0 + _events_count) {
             while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
                 TranslateMessage(&msg);
                 DispatchMessage(&msg);
             }
+            continue;
+        }
+        switch (wait_ret) {
+        case WAIT_OBJECT_0 + VD_EVENT_CONTROL:
+            handle_control_event();
             break;
         case WAIT_IO_COMPLETION:
-            break;
         case WAIT_TIMEOUT:
+            break;
         default:
-            vd_printf("MsgWaitForMultipleObjectsEx(): %lu", wait_ret);
+            DWORD vdi_event = wait_ret - VD_STATIC_EVENTS_COUNT - WAIT_OBJECT_0;
+            if (vdi_event >= 0 && vdi_event < _vdi_port->get_num_events()) {
+                _running = _vdi_port->handle_event(vdi_event);
+            } else {
+                vd_printf("MsgWaitForMultipleObjectsEx failed: %lu %lu", wait_ret, GetLastError());
+                _running = false;
+            }
         }
     }
     _desktop_switch = false;
@@ -399,6 +466,7 @@ void VDAgent::input_desktop_message_loop()
         _pending_input = false;
     }
     ChangeClipboardChain(_hwnd, _hwnd_next_viewer);
+    WTSUnRegisterSessionNotification(_hwnd);
     DestroyWindow(_hwnd);
     CloseDesktop(hdesk);
 }
@@ -512,7 +580,7 @@ bool VDAgent::handle_mouse_event(VDAgentMouseState* state)
 
 bool VDAgent::handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port)
 {
-    VDPipeMessage* reply_pipe_msg;
+    VDIChunk* reply_chunk;
     VDAgentMessage* reply_msg;
     VDAgentReply* reply;
     size_t display_count;
@@ -540,14 +608,13 @@ bool VDAgent::handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port
     }
 
     DWORD msg_size = VD_MESSAGE_HEADER_SIZE + sizeof(VDAgentReply);
-    reply_pipe_msg = new_message(msg_size);
-    if (!reply_pipe_msg) {
+    reply_chunk = new_chunk(msg_size);
+    if (!reply_chunk) {
         return false;
     }
-    reply_pipe_msg->type = VD_AGENT_COMMAND;
-    reply_pipe_msg->opaque = port;
-    reply_pipe_msg->size = sizeof(VDAgentMessage) + sizeof(VDAgentReply);
-    reply_msg = (VDAgentMessage*)reply_pipe_msg->data;
+    reply_chunk->hdr.port = port;
+    reply_chunk->hdr.size = sizeof(VDAgentMessage) + sizeof(VDAgentReply);
+    reply_msg = (VDAgentMessage*)reply_chunk->data;
     reply_msg->protocol = VD_AGENT_PROTOCOL;
     reply_msg->type = VD_AGENT_REPLY;
     reply_msg->opaque = 0;
@@ -555,7 +622,7 @@ bool VDAgent::handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port
     reply = (VDAgentReply*)reply_msg->data;
     reply->type = VD_AGENT_MONITORS_CONFIG;
     reply->error = display_count ? VD_AGENT_SUCCESS : VD_AGENT_ERROR;
-    enqueue_message(reply_pipe_msg);
+    enqueue_chunk(reply_chunk);
     return true;
 }
 
@@ -661,22 +728,21 @@ void VDAgent::load_display_setting()
 bool VDAgent::send_announce_capabilities(bool request)
 {
     DWORD msg_size;
-    VDPipeMessage* caps_pipe_msg;
+    VDIChunk* caps_chunk;
     VDAgentMessage* caps_msg;
     VDAgentAnnounceCapabilities* caps;
     uint32_t caps_size;
     uint32_t internal_msg_size = sizeof(VDAgentAnnounceCapabilities) + VD_AGENT_CAPS_BYTES;
 
     msg_size = VD_MESSAGE_HEADER_SIZE + internal_msg_size;
-    caps_pipe_msg = new_message(msg_size);
-    if (!caps_pipe_msg) {
+    caps_chunk = new_chunk(msg_size);
+    if (!caps_chunk) {
         return false;
     }
     caps_size = VD_AGENT_CAPS_SIZE;
-    caps_pipe_msg->type = VD_AGENT_COMMAND;
-    caps_pipe_msg->opaque = VDP_CLIENT_PORT;
-    caps_pipe_msg->size = sizeof(VDAgentMessage) + internal_msg_size;
-    caps_msg = (VDAgentMessage*)caps_pipe_msg->data;
+    caps_chunk->hdr.port = VDP_CLIENT_PORT;
+    caps_chunk->hdr.size = sizeof(VDAgentMessage) + internal_msg_size;
+    caps_msg = (VDAgentMessage*)caps_chunk->data;
     caps_msg->protocol = VD_AGENT_PROTOCOL;
     caps_msg->type = VD_AGENT_ANNOUNCE_CAPABILITIES;
     caps_msg->opaque = 0;
@@ -693,7 +759,7 @@ bool VDAgent::send_announce_capabilities(bool request)
     for (uint32_t i = 0 ; i < caps_size; ++i) {
         vd_printf("%X", caps->caps[i]);
     }
-    enqueue_message(caps_pipe_msg);
+    enqueue_chunk(caps_chunk);
     return true;
 }
 
@@ -722,7 +788,7 @@ bool VDAgent::handle_announce_capabilities(VDAgentAnnounceCapabilities* announce
 bool VDAgent::handle_display_config(VDAgentDisplayConfig* display_config, uint32_t port)
 {
     DisplaySettingOptions disp_setting_opts;
-    VDPipeMessage* reply_pipe_msg;
+    VDIChunk* reply_chunk;
     VDAgentMessage* reply_msg;
     VDAgentReply* reply;
     DWORD msg_size;
@@ -746,14 +812,13 @@ bool VDAgent::handle_display_config(VDAgentDisplayConfig* display_config, uint32
     }
 
     msg_size = VD_MESSAGE_HEADER_SIZE + sizeof(VDAgentReply);
-    reply_pipe_msg = new_message(msg_size);
-    if (!reply_pipe_msg) {
+    reply_chunk = new_chunk(msg_size);
+    if (!reply_chunk) {
         return false;
     }
-    reply_pipe_msg->type = VD_AGENT_COMMAND;
-    reply_pipe_msg->opaque = port;
-    reply_pipe_msg->size = sizeof(VDAgentMessage) + sizeof(VDAgentReply);
-    reply_msg = (VDAgentMessage*)reply_pipe_msg->data;
+    reply_chunk->hdr.port = port;
+    reply_chunk->hdr.size = sizeof(VDAgentMessage) + sizeof(VDAgentReply);
+    reply_msg = (VDAgentMessage*)reply_chunk->data;
     reply_msg->protocol = VD_AGENT_PROTOCOL;
     reply_msg->type = VD_AGENT_REPLY;
     reply_msg->opaque = 0;
@@ -761,50 +826,12 @@ bool VDAgent::handle_display_config(VDAgentDisplayConfig* display_config, uint32
     reply = (VDAgentReply*)reply_msg->data;
     reply->type = VD_AGENT_DISPLAY_CONFIG;
     reply->error = VD_AGENT_SUCCESS;
-    enqueue_message(reply_pipe_msg);
-    return true;
-}
-
-bool VDAgent::handle_control(VDPipeMessage* msg)
-{
-    switch (msg->type) {
-    case VD_AGENT_RESET: {
-        vd_printf("Agent reset");
-        VDPipeMessage* ack = new_message(sizeof(VDPipeMessage));
-        if (!ack) {
-            return false;
-        }
-        ack->type = VD_AGENT_RESET_ACK;
-        ack->opaque = msg->opaque;
-        enqueue_message(ack);
-        break;
-    }
-    case VD_AGENT_SESSION_LOGON:
-        vd_printf("session logon");
-        // loading the display settings for the current session's logged on user only
-        // after 1) we receive logon event, and 2) the desktop switched from Winlogon
-        if (!_logon_desktop) {
-            vd_printf("LOGON display setting");
-            _display_setting.load();
-        } else {
-            _logon_occured = true;
-        }
-        break;
-    case VD_AGENT_QUIT:
-        vd_printf("Agent quit");
-        _running = false;
-        break;
-    default:
-        vd_printf("Unsupported control %u", msg->type);
-        return false;
-    }
+    enqueue_chunk(reply_chunk);
     return true;
 }
 
 #define MIN(a, b) ((a) > (b) ? (b) : (a))
 
-//FIXME: division to max size chunks should NOT be here, but in the service
-//       here we should write the max possible size to the pipe
 bool VDAgent::write_clipboard(VDAgentMessage* msg, uint32_t size)
 {
     uint32_t pos = 0;
@@ -814,18 +841,17 @@ bool VDAgent::write_clipboard(VDAgentMessage* msg, uint32_t size)
     //FIXME: do it smarter - no loop, no memcopy
     MUTEX_LOCK(_message_mutex);
     while (pos < size) {
-        DWORD n = MIN(sizeof(VDPipeMessage) + size - pos, VD_AGENT_MAX_DATA_SIZE);
-        VDPipeMessage* pipe_msg = new_message(n);
-        if (!pipe_msg) {
+        DWORD n = MIN(sizeof(VDIChunk) + size - pos, VD_AGENT_MAX_DATA_SIZE);
+        VDIChunk* chunk = new_chunk(n);
+        if (!chunk) {
             ret = false;
             break;
         }
-        pipe_msg->type = VD_AGENT_COMMAND;
-        pipe_msg->opaque = VDP_CLIENT_PORT;
-        pipe_msg->size = n - sizeof(VDPipeMessage);
-        memcpy(pipe_msg->data, (char*)msg + pos, n - sizeof(VDPipeMessage));
-        enqueue_message(pipe_msg);
-        pos += (n - sizeof(VDPipeMessage));
+        chunk->hdr.port = VDP_CLIENT_PORT;
+        chunk->hdr.size = n - sizeof(VDIChunk);
+        memcpy(chunk->data, (char*)msg + pos, n - sizeof(VDIChunk));
+        enqueue_chunk(chunk);
+        pos += (n - sizeof(VDIChunk));
     }
     MUTEX_UNLOCK(_message_mutex);
     return ret;
@@ -833,17 +859,16 @@ bool VDAgent::write_clipboard(VDAgentMessage* msg, uint32_t size)
 
 bool VDAgent::write_message(uint32_t type, uint32_t size = 0, void* data = NULL)
 {
-    VDPipeMessage* pipe_msg;
+    VDIChunk* chunk;
     VDAgentMessage* msg;
 
-    pipe_msg = new_message(VD_MESSAGE_HEADER_SIZE + size);
-    if (!pipe_msg) {
+    chunk = new_chunk(VD_MESSAGE_HEADER_SIZE + size);
+    if (!chunk) {
         return false;
     }
-    pipe_msg->type = VD_AGENT_COMMAND;
-    pipe_msg->opaque = VDP_CLIENT_PORT;
-    pipe_msg->size = sizeof(VDAgentMessage) + size;
-    msg = (VDAgentMessage*)pipe_msg->data;
+    chunk->hdr.port = VDP_CLIENT_PORT;
+    chunk->hdr.size = sizeof(VDAgentMessage) + size;
+    msg = (VDAgentMessage*)chunk->data;
     msg->protocol = VD_AGENT_PROTOCOL;
     msg->type = type;
     msg->opaque = 0;
@@ -851,7 +876,7 @@ bool VDAgent::write_message(uint32_t type, uint32_t size = 0, void* data = NULL)
     if (size && data) {
         memcpy(msg->data, data, size);
     }
-    enqueue_message(pipe_msg);
+    enqueue_chunk(chunk);
     return true;
 }
 
@@ -1119,32 +1144,29 @@ void VDAgent::set_clipboard_owner(int new_owner)
     _clipboard_owner = new_owner;
 }
 
-bool VDAgent::connect_pipe()
+VDIPort *create_virtio_vdi_port()
 {
-    VDAgent* a = _singleton;
-    HANDLE pipe;
+    return new VirtioVDIPort();
+}
 
-    ZeroMemory(&a->_pipe_state, sizeof(VDPipeState));
-    if (!WaitNamedPipe(VD_SERVICE_PIPE_NAME, NMPWAIT_USE_DEFAULT_WAIT)) {
-        vd_printf("WaitNamedPipe() failed: %lu", GetLastError());
-        return false;
-    }
-    //assuming vdservice created the named pipe before creating this vdagent process
-    pipe = CreateFile(VD_SERVICE_PIPE_NAME, GENERIC_READ | GENERIC_WRITE,
-                      0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
-    if (pipe == INVALID_HANDLE_VALUE) {
-        vd_printf("CreateFile() failed: %lu", GetLastError());
-        return false;
-    }
-    DWORD pipe_mode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
-    if (!SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL)) {
-        vd_printf("SetNamedPipeHandleState() failed: %lu", GetLastError());
-        CloseHandle(pipe);
-        return false;
+VDIPort *create_pci_vdi_port()
+{
+    return new PCIVDIPort();
+}
+
+bool VDAgent::init_vdi_port()
+{
+    VDIPort* (*creators[])(void) = { create_virtio_vdi_port, create_pci_vdi_port };
+
+    for (unsigned int i = 0 ; i < sizeof(creators)/sizeof(creators[0]); ++i) {
+        _vdi_port = creators[i]();
+        if (_vdi_port->init()) {
+            return true;
+        }
+        delete _vdi_port;
     }
-    a->_pipe_state.pipe = pipe;
-    vd_printf("Connected to service pipe");
-    return true;
+    _vdi_port = NULL;
+    return false;
 }
 
 void VDAgent::dispatch_message(VDAgentMessage* msg, uint32_t port)
@@ -1190,143 +1212,105 @@ void VDAgent::dispatch_message(VDAgentMessage* msg, uint32_t port)
     }
 }
 
-VOID CALLBACK VDAgent::read_completion(DWORD err, DWORD bytes, LPOVERLAPPED overlap)
+void VDAgent::handle_port_in()
 {
-    VDAgent* a = _singleton;
-    VDPipeState* ps = &a->_pipe_state;
-    DWORD len;
-
-    if (!a->_running) {
-        return;
-    }
-    if (err) {
-        vd_printf("vdservice disconnected (%lu)", err);
-        a->_running = false;
-        return;
-    }
-    ps->read.end += bytes;
-    while (a->_running && (len = ps->read.end - ps->read.start) >= sizeof(VDPipeMessage)) {
-        VDPipeMessage* pipe_msg = (VDPipeMessage*)&ps->read.data[ps->read.start];
-
-        if (pipe_msg->type != VD_AGENT_COMMAND) {
-            a->handle_control(pipe_msg);
-            ps->read.start += sizeof(VDPipeMessage);
-            continue;
-        }
-        if (len < sizeof(VDPipeMessage) + pipe_msg->size) {
-            break;
-        }
-
-        //FIXME: currently assumes that multi-part msg arrives only from client port
-        if (a->_in_msg_pos == 0 || pipe_msg->opaque == VDP_SERVER_PORT) {
-            if (len < VD_MESSAGE_HEADER_SIZE) {
+    static char buf[sizeof(VDIChunk) + VD_AGENT_MAX_DATA_SIZE] = {0, };
+    VDIChunk* chunk = (VDIChunk*)buf;
+    uint32_t chunk_size;
+
+    while (_running)  {
+        if (!chunk->hdr.size && _vdi_port->read_ring_size() >= sizeof(VDIChunk)) {
+            if (_vdi_port->ring_read(chunk, sizeof(VDIChunk)) != sizeof(VDIChunk)) {
+                vd_printf("ring_read of chunk header failed");
+                _running = false;
                 break;
             }
-            VDAgentMessage* msg = (VDAgentMessage*)pipe_msg->data;
-            if (msg->protocol != VD_AGENT_PROTOCOL) {
-                vd_printf("Invalid protocol %u bytes %lu", msg->protocol, bytes);
-                a->_running = false;
+            if (sizeof(VDIChunk) + chunk->hdr.size > sizeof(buf)) {
+                vd_printf("chunk is too large, size %u port %u", chunk->hdr.size, chunk->hdr.port);
+                _running = false;
                 break;
             }
-            uint32_t msg_size = sizeof(VDAgentMessage) + msg->size;
-            if (pipe_msg->size == msg_size) {
-                dispatch_message(msg, pipe_msg->opaque);
-            } else {
-                ASSERT(pipe_msg->size < msg_size);
-                a->_in_msg = (VDAgentMessage*)new uint8_t[msg_size];
-                memcpy(a->_in_msg, pipe_msg->data, pipe_msg->size);
-                a->_in_msg_pos = pipe_msg->size;
-            }
-        } else {
-            memcpy((uint8_t*)a->_in_msg + a->_in_msg_pos, pipe_msg->data, pipe_msg->size);
-            a->_in_msg_pos += pipe_msg->size;
-            if (a->_in_msg_pos == sizeof(VDAgentMessage) + a->_in_msg->size) {
-                dispatch_message(a->_in_msg, 0);
-                a->_in_msg_pos = 0;
-                delete[] (uint8_t *)a->_in_msg;
-                a->_in_msg = NULL;
-            }
         }
-
-        ps->read.start += (sizeof(VDPipeMessage) + pipe_msg->size);
-        if (ps->read.start == ps->read.end) {
-            ps->read.start = ps->read.end = 0;
+        chunk_size = chunk->hdr.size;
+        if (!chunk_size || _vdi_port->read_ring_size() < chunk_size) {
+            break;
         }
-    }
-    if (a->_running && ps->read.end < sizeof(ps->read.data) &&
-        !ReadFileEx(ps->pipe, ps->read.data + ps->read.end, sizeof(ps->read.data) - ps->read.end,
-                    overlap, read_completion)) {
-        vd_printf("ReadFileEx() failed: %lu", GetLastError());
-        a->_running = false;
-    }
+        if (_vdi_port->ring_read(chunk->data, chunk_size) != chunk_size) {
+            vd_printf("ring_read of chunk data failed");
+            _running = false;
+            break;
+        }
+        handle_chunk(chunk);
+        chunk->hdr.size = 0;
+   }
 }
 
-VOID CALLBACK VDAgent::write_completion(DWORD err, DWORD bytes, LPOVERLAPPED overlap)
+void VDAgent::handle_chunk(VDIChunk* chunk)
 {
-    VDAgent* a = _singleton;
-    VDPipeState* ps = &a->_pipe_state;
-    DWORD size_left;
-
-    if (!a->_running) {
-        return;
-    }
-    if (err) {
-        vd_printf("vdservice disconnected (%lu)", err);
-        a->_running = false;
-        return;
-    }
-    MUTEX_LOCK(a->_write_mutex);
-    ps->write.start += bytes;
-    if (ps->write.start == ps->write.end) {
-        ps->write.start = ps->write.end = 0;
+    //FIXME: currently assumes that multi-part msg arrives only from client port
+    if (_in_msg_pos == 0 || chunk->hdr.port == VDP_SERVER_PORT) {
+        if (chunk->hdr.size < sizeof(VDAgentMessage)) {
+            return;
+        }
+        VDAgentMessage* msg = (VDAgentMessage*)chunk->data;
+        if (msg->protocol != VD_AGENT_PROTOCOL) {
+            vd_printf("Invalid protocol %u", msg->protocol);
+            _running = false;
+            return;
+        }
+        uint32_t msg_size = sizeof(VDAgentMessage) + msg->size;
+        if (chunk->hdr.size == msg_size) {
+            dispatch_message(msg, chunk->hdr.port);
+        } else {
+            ASSERT(chunk->hdr.size < msg_size);
+            _in_msg = (VDAgentMessage*)new uint8_t[msg_size];
+            memcpy(_in_msg, chunk->data, chunk->hdr.size);
+            _in_msg_pos = chunk->hdr.size;
+        }
+    } else {
+        memcpy((uint8_t*)_in_msg + _in_msg_pos, chunk->data, chunk->hdr.size);
+        _in_msg_pos += chunk->hdr.size;
+        if (_in_msg_pos == sizeof(VDAgentMessage) + _in_msg->size) {
+            dispatch_message(_in_msg, 0);
+            _in_msg_pos = 0;
+            delete[] (uint8_t *)_in_msg;
+            _in_msg = NULL;
+        }
     }
+}
 
-    MUTEX_LOCK(a->_message_mutex);
-    size_left = sizeof(a->_pipe_state.write.data) - a->_pipe_state.write.end;
-    while (!a->_message_queue.empty()) {
-        VDPipeMessage* msg = a->_message_queue.front();
-        DWORD size = sizeof(VDPipeMessage) + msg->size;
+void VDAgent::handle_port_out()
+{
+    MUTEX_LOCK(_message_mutex);
+    while (_running && !_message_queue.empty()) {
+        VDIChunk* chunk = _message_queue.front();
+        DWORD size = sizeof(VDIChunk) + chunk->hdr.size;
 
-        if (size > size_left) {
+        if (size > _vdi_port->write_ring_free_space()) {
             break;
         }
-        a->_message_queue.pop();
-        memcpy(a->_pipe_state.write.data + a->_pipe_state.write.end, msg, size);
-        a->_pipe_state.write.end += size;
-        size_left -= size;
-        delete msg;
-    }
-    MUTEX_UNLOCK(a->_message_mutex);
-
-    if (ps->write.start < ps->write.end) {
-        if (WriteFileEx(ps->pipe, ps->write.data + ps->write.start,
-                               ps->write.end - ps->write.start, overlap, write_completion)) {
-            a->_pending_write = true;
-        } else {
-            vd_printf("WriteFileEx() failed: %lu", GetLastError());
-            a->_running = false;
+        _message_queue.pop();
+        if (_vdi_port->ring_write(chunk, size) != size) {
+            vd_printf("ring_write failed");
+            _running = false;
+            return;
         }
-    } else {
-        a->_pending_write = false;
+        delete chunk;
     }
-    MUTEX_UNLOCK(a->_write_mutex);
+    MUTEX_UNLOCK(_message_mutex);
 }
 
-VDPipeMessage* VDAgent::new_message(DWORD bytes)
+VDIChunk* VDAgent::new_chunk(DWORD bytes)
 {
-    return (VDPipeMessage*)(new char[bytes]);
+    return (VDIChunk*)(new char[bytes]);
 }
 
-void VDAgent::enqueue_message(VDPipeMessage* msg)
+void VDAgent::enqueue_chunk(VDIChunk* chunk)
 {
     MUTEX_LOCK(_message_mutex);
-    _message_queue.push(msg);
+    _message_queue.push(chunk);
     MUTEX_UNLOCK(_message_mutex);
-    MUTEX_LOCK(_write_mutex);
-    if (!_pending_write) {
-        write_completion(0, 0, &_pipe_state.write.overlap);
-    }
-    MUTEX_UNLOCK(_write_mutex);
+    handle_port_out();
 }
 
 LRESULT CALLBACK VDAgent::wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
@@ -1369,6 +1353,11 @@ LRESULT CALLBACK VDAgent::wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARA
             a->set_control_event(CONTROL_STOP);
         }
         break;
+    case WM_WTSSESSION_CHANGE:
+        if (wparam == WTS_SESSION_LOGON) {
+            a->set_control_event(CONTROL_LOGON);
+        }
+        break;
     default:
         return DefWindowProc(hwnd, message, wparam, lparam);
     }
diff --git a/vdagent/vdagent.vcproj b/vdagent/vdagent.vcproj
index 151a643..b99297e 100644
--- a/vdagent/vdagent.vcproj
+++ b/vdagent/vdagent.vcproj
@@ -65,7 +65,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="Version.lib zlibwapiD.lib png_d.lib cximage_d.lib"
+				AdditionalDependencies="Version.lib zlibwapiD.lib png_d.lib cximage_d.lib wtsapi32.lib"
 				LinkIncremental="2"
 				AdditionalLibraryDirectories=""$(SPICE_LIBS)\lib""
 				GenerateDebugInformation="true"
@@ -143,7 +143,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="Version.lib zlibwapiD.lib png_d.lib cximage_d.lib"
+				AdditionalDependencies="Version.lib zlibwapiD.lib png_d.lib cximage_d.lib wtsapi32.lib"
 				LinkIncremental="2"
 				AdditionalLibraryDirectories=""$(SPICE_LIBS)\lib64""
 				IgnoreDefaultLibraryNames=""
@@ -220,7 +220,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="Version.lib zlibwapi.lib png.lib cximage.lib"
+				AdditionalDependencies="Version.lib zlibwapi.lib png.lib cximage.lib wtsapi32.lib"
 				LinkIncremental="1"
 				AdditionalLibraryDirectories=""$(SPICE_LIBS)\lib""
 				GenerateDebugInformation="true"
@@ -299,7 +299,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="Version.lib zlibwapi.lib png.lib cximage.lib"
+				AdditionalDependencies="Version.lib zlibwapi.lib png.lib cximage.lib wtsapi32.lib"
 				LinkIncremental="1"
 				AdditionalLibraryDirectories=""$(SPICE_LIBS)\lib64""
 				GenerateDebugInformation="true"
@@ -350,13 +350,25 @@
 				>
 			</File>
 			<File
+				RelativePath=".\pci_vdi_port.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\vdagent.cpp"
 				>
 			</File>
 			<File
+				RelativePath=".\vdi_port.cpp"
+				>
+			</File>
+			<File
 				RelativePath="..\common\vdlog.cpp"
 				>
 			</File>
+			<File
+				RelativePath=".\virtio_vdi_port.cpp"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="Header Files"
@@ -372,6 +384,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\pci_vdi_port.h"
+				>
+			</File>
+			<File
 				RelativePath=".\resource.h"
 				>
 			</File>
@@ -380,9 +396,17 @@
 				>
 			</File>
 			<File
+				RelativePath=".\vdi_port.h"
+				>
+			</File>
+			<File
 				RelativePath="..\common\vdlog.h"
 				>
 			</File>
+			<File
+				RelativePath=".\virtio_vdi_port.h"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="Resource Files"
commit 3f7d4da4bcb0a376e05b4864ebfc1dc6d8905c7d
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Tue Nov 6 12:28:03 2012 +0200

    vdagent: mv vdi_port files from vdservice

diff --git a/vdagent/pci_vdi_port.cpp b/vdagent/pci_vdi_port.cpp
new file mode 100644
index 0000000..7466fbc
--- /dev/null
+++ b/vdagent/pci_vdi_port.cpp
@@ -0,0 +1,132 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdio.h"
+#include "pci_vdi_port.h"
+#include "vdlog.h"
+
+#define VDI_PORT_DEV_NAME   TEXT("\\\\.\\VDIPort")
+#define FILE_DEVICE_UNKNOWN 0x00000022
+#define METHOD_BUFFERED     0
+#define FILE_ANY_ACCESS     0
+
+#ifndef CTL_CODE
+//With mingw, this is defined in winioctl.h
+#define CTL_CODE(DeviceType, Function, Method, Access) (                   \
+    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
+)
+#endif
+
+#define FIRST_AVAIL_IO_FUNC 0x800
+#define RED_TUNNEL_CTL_FUNC FIRST_AVAIL_IO_FUNC
+
+#define IOCTL_RED_TUNNEL_SET_EVENT \
+    CTL_CODE(FILE_DEVICE_UNKNOWN, RED_TUNNEL_CTL_FUNC, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+
+PCIVDIPort::PCIVDIPort()
+    : _handle (INVALID_HANDLE_VALUE)
+    , _event (NULL)
+{
+}
+
+PCIVDIPort::~PCIVDIPort()
+{
+    if (_handle != INVALID_HANDLE_VALUE) {
+        CloseHandle(_handle);
+    }
+    if (_event) {
+        CloseHandle(_event);
+    }
+}
+
+void PCIVDIPort::fill_events(HANDLE* handles) {
+    handles[PCI_VDI_PORT_EVENT] = _event;
+}
+
+bool PCIVDIPort::init()
+{
+    DWORD io_ret_len;
+    _handle = CreateFile(VDI_PORT_DEV_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                         OPEN_EXISTING, 0, NULL);
+    if (_handle == INVALID_HANDLE_VALUE) {
+        vd_printf("CreateFile() failed: %lu", GetLastError());
+        return false;
+    }
+    _event = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (_event == NULL) {
+        vd_printf("CreateEvent() failed: %lu", GetLastError());
+        return false;
+    }
+    if (!DeviceIoControl(_handle, IOCTL_RED_TUNNEL_SET_EVENT, &_event, sizeof(_event),
+                         NULL, 0, &io_ret_len, NULL)) {
+        vd_printf("DeviceIoControl() failed: %lu", GetLastError());
+        return false;
+    }
+    return true;
+}
+
+int PCIVDIPort::write()
+{
+    int size;
+    int n;
+
+    if (_write.start == _write.end) {
+        return 0;
+    }
+    if (_write.start < _write.end) {
+        size = (int)(_write.end - _write.start);
+    } else {
+        size = (int)(&_write.ring[BUF_SIZE] - _write.start);
+    }
+    if (!WriteFile(_handle, _write.start, size, (LPDWORD)&n, NULL)) {
+        return handle_error();
+    }
+    _write.start = _write.ring + (_write.start - _write.ring + n) % BUF_SIZE;
+    return n;
+}
+
+int PCIVDIPort::read()
+{
+    int size;
+    int n;
+
+    if ((_read.end - _read.ring + 1) % BUF_SIZE == _read.start - _read.ring) {
+        return 0;
+    }
+    if (_read.start == _read.end) {
+        _read.start = _read.end = _read.ring;
+    }
+    if (_read.start <= _read.end) {
+        size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end));
+    } else {
+        size = (int)(_read.start - _read.end - 1);
+    }
+    if (!ReadFile(_handle, _read.end, size, (LPDWORD)&n, NULL)) {
+        return handle_error();
+    }
+    _read.end = _read.ring + (_read.end - _read.ring + n) % BUF_SIZE;
+    return n;
+}
+
+bool PCIVDIPort::handle_event(int event)
+{
+    // do nothing - the event merely serves to wake us up, then we call read/write
+    // at VDService::execute start of while(_running) loop.
+    return true;
+}
diff --git a/vdagent/pci_vdi_port.h b/vdagent/pci_vdi_port.h
new file mode 100644
index 0000000..fcc76dc
--- /dev/null
+++ b/vdagent/pci_vdi_port.h
@@ -0,0 +1,59 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _H_PCI_VDI_PORT
+#define _H_PCI_VDI_PORT
+
+#include "vdi_port.h"
+
+#define BUF_READ    (1 << 0)
+#define BUF_WRITE   (1 << 1)
+#define BUF_ALL     (BUF_READ | BUF_WRITE)
+
+enum {
+    PCI_VDI_PORT_EVENT = 0,
+    PCI_VDI_PORT_EVENT_COUNT
+};
+
+class PCIVDIPort : public VDIPort {
+public:
+    PCIVDIPort();
+    ~PCIVDIPort();
+    virtual bool init();
+    virtual const char *name() {
+        return "PCIVDIPort";
+    }
+    virtual int write();
+    virtual int read();
+    virtual unsigned get_num_events() { return PCI_VDI_PORT_EVENT_COUNT; }
+    virtual void fill_events(HANDLE* handles);
+    virtual bool handle_event(int event);
+
+private:
+    HANDLE _handle;
+    HANDLE _event;
+};
+
+// Ring notes:
+// _end is one after the end of data
+// _start==_end means empty ring
+// _start-1==_end (modulo) means full ring
+// _start-1 is never used
+// ring_write & read on right side of the ring (update _end)
+// ring_read & write from left (update _start)
+
+#endif
diff --git a/vdagent/vdi_port.cpp b/vdagent/vdi_port.cpp
new file mode 100644
index 0000000..bd5ea05
--- /dev/null
+++ b/vdagent/vdi_port.cpp
@@ -0,0 +1,90 @@
+#include "vdlog.h"
+#include "vdi_port.h"
+
+VDIPort::VDIPort()
+{
+    ZeroMemory(&_write, offsetof(VDIPortBuffer, ring));
+    _write.start = _write.end = _write.ring;
+    ZeroMemory(&_read, offsetof(VDIPortBuffer, ring));
+    _read.start = _read.end = _read.ring;
+}
+
+size_t VDIPort::read_ring_size()
+{
+    return (BUF_SIZE + _read.end - _read.start) % BUF_SIZE;
+}
+
+size_t VDIPort::write_ring_free_space()
+{
+    return (BUF_SIZE + _write.start - _write.end - 1) % BUF_SIZE;
+}
+
+size_t VDIPort::ring_write(const void* buf, size_t size)
+{
+    size_t free_size = (BUF_SIZE + _write.start - _write.end - 1) % BUF_SIZE;
+    size_t n;
+
+    if (size > free_size) {
+        size = free_size;
+    }
+    if (_write.end < _write.start) {
+        memcpy(_write.end, buf, size);
+    } else {
+        n = MIN(size, (size_t)(&_write.ring[BUF_SIZE] - _write.end));
+        memcpy(_write.end, buf, n);
+        if (size > n) {
+            memcpy(_write.ring, (uint8_t*)buf + n, size - n);
+        }
+    }
+    _write.end = _write.ring + (_write.end - _write.ring + size) % BUF_SIZE;
+    return size;
+}
+
+size_t VDIPort::read_ring_continuous_remaining_size()
+{
+    DWORD size;
+
+    if (_read.start <= _read.end) {
+        size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end));
+    } else {
+        size = (DWORD)(_read.start - _read.end - 1);
+    }
+    return size;
+}
+
+size_t VDIPort::ring_read(void* buf, size_t size)
+{
+    size_t n;
+    size_t m = 0;
+
+    if (_read.start == _read.end) {
+        return 0;
+    }
+    if (_read.start < _read.end) {
+        n = MIN(size, (size_t)(_read.end - _read.start));
+        memcpy(buf, _read.start, n);
+    } else {
+        n = MIN(size, (size_t)(&_read.ring[BUF_SIZE] - _read.start));
+        memcpy(buf, _read.start, n);
+        if (size > n) {
+            m = MIN(size - n, (size_t)(_read.end - _read.ring));
+            memcpy((uint8_t*)buf + n, _read.ring, m);
+        }
+    }
+    _read.start = _read.ring + (_read.start - _read.ring + n + m) % BUF_SIZE;
+    return n + m;
+}
+
+int VDIPort::handle_error()
+{
+    switch (GetLastError()) {
+    case ERROR_CONNECTION_INVALID:
+        vd_printf("port reset");
+        _write.start = _write.end = _write.ring;
+        _read.start = _read.end = _read.ring;
+        return VDI_PORT_RESET;
+    default:
+        vd_printf("port io failed: %lu", GetLastError());
+        return VDI_PORT_ERROR;
+    }
+}
diff --git a/vdagent/vdi_port.h b/vdagent/vdi_port.h
new file mode 100644
index 0000000..a0fb20e
--- /dev/null
+++ b/vdagent/vdi_port.h
@@ -0,0 +1,75 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _H_VDI_PORT
+#define _H_VDI_PORT
+
+#include <windows.h>
+#include <stdint.h>
+
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+
+#define BUF_SIZE    (1024 * 1024)
+
+#define VDI_PORT_BLOCKED    0
+#define VDI_PORT_RESET      -1
+#define VDI_PORT_ERROR      -2
+
+// Ring notes:
+// _end is one after the end of data
+// _start==_end means empty ring
+// _start-1==_end (modulo) means full ring
+// _start-1 is never used
+// ring_write & read on right side of the ring (update _end)
+// ring_read & write from left (update _start)
+
+typedef struct VDIPortBuffer {
+    OVERLAPPED overlap;
+    uint8_t* start;
+    uint8_t* end;
+    bool pending;
+    int bytes;
+    uint8_t ring[BUF_SIZE];
+} VDIPortBuffer;
+
+class VDIPort {
+public:
+    VDIPort();
+    virtual ~VDIPort() {}
+
+    size_t ring_write(const void* buf, size_t size);
+    size_t write_ring_free_space();
+    size_t ring_read(void* buf, size_t size);
+    size_t read_ring_size();
+    size_t read_ring_continuous_remaining_size();
+
+    virtual const char *name() = 0;
+    virtual bool init() = 0;
+    virtual unsigned get_num_events() = 0;
+    virtual void fill_events(HANDLE* handles) = 0;
+    virtual bool handle_event(int event) = 0;
+    virtual int write() = 0;
+    virtual int read() = 0;
+
+protected:
+    int handle_error();
+
+    VDIPortBuffer _write;
+    VDIPortBuffer _read;
+};
+
+#endif
diff --git a/vdagent/virtio_vdi_port.cpp b/vdagent/virtio_vdi_port.cpp
new file mode 100644
index 0000000..be5568a
--- /dev/null
+++ b/vdagent/virtio_vdi_port.cpp
@@ -0,0 +1,187 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdio.h"
+#include "virtio_vdi_port.h"
+#include "vdlog.h"
+
+#define VIOSERIAL_PORT_PATH                 L"\\\\.\\Global\\com.redhat.spice.0"
+
+// Current limitation of virtio-serial windows driver (RHBZ 617000)
+#define VIOSERIAL_PORT_MAX_WRITE_BYTES      2048
+
+VirtioVDIPort* VirtioVDIPort::_singleton;
+
+VirtioVDIPort::VirtioVDIPort()
+    : VDIPort()
+    , _handle (INVALID_HANDLE_VALUE)
+{
+    _singleton = this;
+}
+
+VirtioVDIPort::~VirtioVDIPort()
+{
+    if (_handle != INVALID_HANDLE_VALUE) {
+        CloseHandle(_handle);
+    }
+    if (_read.overlap.hEvent) {
+        CloseHandle(_read.overlap.hEvent);
+    }
+    if (_write.overlap.hEvent) {
+        CloseHandle(_write.overlap.hEvent);
+    }
+}
+
+void VirtioVDIPort::fill_events(HANDLE* handles) {
+    handles[VIRTIO_VDI_PORT_EVENT_WRITE] = _write.overlap.hEvent;
+    handles[VIRTIO_VDI_PORT_EVENT_READ] = _read.overlap.hEvent;
+}
+
+bool VirtioVDIPort::handle_event(int event) {
+    bool ret;
+
+    switch (event) {
+        case VIRTIO_VDI_PORT_EVENT_WRITE:
+            ret = write_completion();
+            break;
+        case VIRTIO_VDI_PORT_EVENT_READ:
+            ret = read_completion();
+            break;
+        default:
+            vd_printf("ERROR: unexpected event %d", event);
+            ret = false;
+    }
+    return ret;
+}
+
+bool VirtioVDIPort::init()
+{
+    _handle = CreateFile(VIOSERIAL_PORT_PATH, GENERIC_READ | GENERIC_WRITE , 0, NULL,
+                         OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+    if (_handle == INVALID_HANDLE_VALUE) {
+        vd_printf("CreateFile() %ls failed: %lu", VIOSERIAL_PORT_PATH, GetLastError());
+        return false;
+    }
+    _write.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (_write.overlap.hEvent == NULL) {
+        vd_printf("CreateEvent() failed: %lu", GetLastError());
+        return false;
+    }
+    _read.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (_read.overlap.hEvent == NULL) {
+        vd_printf("CreateEvent() failed: %lu", GetLastError());
+        return false;
+    }
+    return true;
+}
+
+int VirtioVDIPort::write()
+{
+    int size;
+    int ret;
+
+    //FIXME: return VDI_PORT_NO_DATA
+    if (_write.start == _write.end) {
+        return 0;
+    }
+    if (!_write.pending) {
+        if (_write.start < _write.end) {
+            size = (int)(_write.end - _write.start);
+        } else {
+            size = (int)(&_write.ring[BUF_SIZE] - _write.start);
+        }
+        size = MIN(size, VIOSERIAL_PORT_MAX_WRITE_BYTES);
+        _write.pending = true;
+        if (WriteFile(_handle, _write.start, size, NULL, &_write.overlap)) {
+            write_completion();
+        } if (GetLastError() != ERROR_IO_PENDING) {
+            return handle_error();
+        }
+    }
+    ret = _write.bytes;
+    _write.bytes = 0;
+    return ret;
+}
+
+bool VirtioVDIPort::write_completion()
+{
+    DWORD bytes;
+
+    if (!_write.pending) {
+        return true;
+    }
+    if (!GetOverlappedResult(_handle, &_write.overlap, &bytes, FALSE)) {
+        vd_printf("GetOverlappedResult failed: %lu", GetLastError());
+        return false;
+    }
+    _write.start = _write.ring + (_write.start - _write.ring + bytes) % BUF_SIZE;
+    _write.bytes = bytes;
+    _write.pending = false;
+    return true;
+}
+
+int VirtioVDIPort::read()
+{
+    int size;
+    int ret;
+
+    if (!_read.pending) {
+        //FIXME: read_ring_continuous_remaining_size? return VDI_PORT_BUFFER_FULL
+        if ((_read.end - _read.ring + 1) % BUF_SIZE == _read.start - _read.ring) {
+            vd_printf("DEBUG: buffer full");
+            return 0;
+        }
+        if (_read.start == _read.end) {
+            _read.start = _read.end = _read.ring;
+        }
+        if (_read.start <= _read.end) {
+            size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end));
+        } else {
+            size = (int)(_read.start - _read.end - 1);
+        }
+        _read.pending = true;
+        if (ReadFile(_handle, _read.end, size, NULL, &_read.overlap)) {
+            read_completion();
+        } else if (GetLastError() != ERROR_IO_PENDING) {
+            return handle_error();
+        }
+    }
+    ret = _read.bytes;
+    _read.bytes = 0;
+    return ret;
+}
+
+bool VirtioVDIPort::read_completion()
+{
+    DWORD bytes;
+
+    if (!GetOverlappedResult(_handle, &_read.overlap, &bytes, FALSE)) {
+        DWORD err = GetLastError();
+
+        if (err == ERROR_OPERATION_ABORTED || err == ERROR_NO_SYSTEM_RESOURCES) {
+            _read.pending = false;
+            return true;
+        } else if (err != ERROR_MORE_DATA) {
+            vd_printf("GetOverlappedResult failed: %lu", err);
+            return false;
+        }
+    }
+    _read.end = _read.ring + (_read.end - _read.ring + bytes) % BUF_SIZE;
+    _read.bytes = bytes;
+    _read.pending = false;
+    return true;
+}
diff --git a/vdagent/virtio_vdi_port.h b/vdagent/virtio_vdi_port.h
new file mode 100644
index 0000000..d72edf4
--- /dev/null
+++ b/vdagent/virtio_vdi_port.h
@@ -0,0 +1,33 @@
+#ifndef _H_VIRTIO_VDI_PORT
+#define _H_VIRTIO_VDI_PORT
+
+#include "vdi_port.h"
+
+enum {
+    VIRTIO_VDI_PORT_EVENT_WRITE=0,
+    VIRTIO_VDI_PORT_EVENT_READ,
+    VIRTIO_VDI_PORT_EVENT_COUNT
+};
+
+class VirtioVDIPort : public VDIPort {
+public:
+    VirtioVDIPort();
+    ~VirtioVDIPort();
+    virtual const char *name() { return "VirtioVDIPort"; }
+    virtual bool init();
+    virtual unsigned get_num_events() { return VIRTIO_VDI_PORT_EVENT_COUNT; }
+    virtual void fill_events(HANDLE* handles);
+    virtual bool handle_event(int event);
+    virtual int write();
+    virtual int read();
+
+private:
+    bool write_completion();
+    bool read_completion();
+
+private:
+    static VirtioVDIPort* _singleton;
+    HANDLE _handle;
+};
+
+#endif //_H_VIRTIO_VDI_PORT
diff --git a/vdservice/pci_vdi_port.cpp b/vdservice/pci_vdi_port.cpp
deleted file mode 100644
index 7466fbc..0000000
--- a/vdservice/pci_vdi_port.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "stdio.h"
-#include "pci_vdi_port.h"
-#include "vdlog.h"
-
-#define VDI_PORT_DEV_NAME   TEXT("\\\\.\\VDIPort")
-#define FILE_DEVICE_UNKNOWN 0x00000022
-#define METHOD_BUFFERED     0
-#define FILE_ANY_ACCESS     0
-
-#ifndef CTL_CODE
-//With mingw, this is defined in winioctl.h
-#define CTL_CODE(DeviceType, Function, Method, Access) (                   \
-    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
-)
-#endif
-
-#define FIRST_AVAIL_IO_FUNC 0x800
-#define RED_TUNNEL_CTL_FUNC FIRST_AVAIL_IO_FUNC
-
-#define IOCTL_RED_TUNNEL_SET_EVENT \
-    CTL_CODE(FILE_DEVICE_UNKNOWN, RED_TUNNEL_CTL_FUNC, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#define MIN(a, b) ((a) > (b) ? (b) : (a))
-
-PCIVDIPort::PCIVDIPort()
-    : _handle (INVALID_HANDLE_VALUE)
-    , _event (NULL)
-{
-}
-
-PCIVDIPort::~PCIVDIPort()
-{
-    if (_handle != INVALID_HANDLE_VALUE) {
-        CloseHandle(_handle);
-    }
-    if (_event) {
-        CloseHandle(_event);
-    }
-}
-
-void PCIVDIPort::fill_events(HANDLE* handles) {
-    handles[PCI_VDI_PORT_EVENT] = _event;
-}
-
-bool PCIVDIPort::init()
-{
-    DWORD io_ret_len;
-    _handle = CreateFile(VDI_PORT_DEV_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL,
-                         OPEN_EXISTING, 0, NULL);
-    if (_handle == INVALID_HANDLE_VALUE) {
-        vd_printf("CreateFile() failed: %lu", GetLastError());
-        return false;
-    }
-    _event = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (_event == NULL) {
-        vd_printf("CreateEvent() failed: %lu", GetLastError());
-        return false;
-    }
-    if (!DeviceIoControl(_handle, IOCTL_RED_TUNNEL_SET_EVENT, &_event, sizeof(_event),
-                         NULL, 0, &io_ret_len, NULL)) {
-        vd_printf("DeviceIoControl() failed: %lu", GetLastError());
-        return false;
-    }
-    return true;
-}
-
-int PCIVDIPort::write()
-{
-    int size;
-    int n;
-
-    if (_write.start == _write.end) {
-        return 0;
-    }
-    if (_write.start < _write.end) {
-        size = (int)(_write.end - _write.start);
-    } else {
-        size = (int)(&_write.ring[BUF_SIZE] - _write.start);
-    }
-    if (!WriteFile(_handle, _write.start, size, (LPDWORD)&n, NULL)) {
-        return handle_error();
-    }
-    _write.start = _write.ring + (_write.start - _write.ring + n) % BUF_SIZE;
-    return n;
-}
-
-int PCIVDIPort::read()
-{
-    int size;
-    int n;
-
-    if ((_read.end - _read.ring + 1) % BUF_SIZE == _read.start - _read.ring) {
-        return 0;
-    }
-    if (_read.start == _read.end) {
-        _read.start = _read.end = _read.ring;
-    }
-    if (_read.start <= _read.end) {
-        size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end));
-    } else {
-        size = (int)(_read.start - _read.end - 1);
-    }
-    if (!ReadFile(_handle, _read.end, size, (LPDWORD)&n, NULL)) {
-        return handle_error();
-    }
-    _read.end = _read.ring + (_read.end - _read.ring + n) % BUF_SIZE;
-    return n;
-}
-
-bool PCIVDIPort::handle_event(int event)
-{
-    // do nothing - the event merely serves to wake us up, then we call read/write
-    // at VDService::execute start of while(_running) loop.
-    return true;
-}
diff --git a/vdservice/pci_vdi_port.h b/vdservice/pci_vdi_port.h
deleted file mode 100644
index fcc76dc..0000000
--- a/vdservice/pci_vdi_port.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _H_PCI_VDI_PORT
-#define _H_PCI_VDI_PORT
-
-#include "vdi_port.h"
-
-#define BUF_READ    (1 << 0)
-#define BUF_WRITE   (1 << 1)
-#define BUF_ALL     (BUF_READ | BUF_WRITE)
-
-enum {
-    PCI_VDI_PORT_EVENT = 0,
-    PCI_VDI_PORT_EVENT_COUNT
-};
-
-class PCIVDIPort : public VDIPort {
-public:
-    PCIVDIPort();
-    ~PCIVDIPort();
-    virtual bool init();
-    virtual const char *name() {
-        return "PCIVDIPort";
-    }
-    virtual int write();
-    virtual int read();
-    virtual unsigned get_num_events() { return PCI_VDI_PORT_EVENT_COUNT; }
-    virtual void fill_events(HANDLE* handles);
-    virtual bool handle_event(int event);
-
-private:
-    HANDLE _handle;
-    HANDLE _event;
-};
-
-// Ring notes:
-// _end is one after the end of data
-// _start==_end means empty ring
-// _start-1==_end (modulo) means full ring
-// _start-1 is never used
-// ring_write & read on right side of the ring (update _end)
-// ring_read & write from left (update _start)
-
-#endif
diff --git a/vdservice/vdi_port.cpp b/vdservice/vdi_port.cpp
deleted file mode 100644
index bd5ea05..0000000
--- a/vdservice/vdi_port.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-#include "vdlog.h"
-#include "vdi_port.h"
-
-VDIPort::VDIPort()
-{
-    ZeroMemory(&_write, offsetof(VDIPortBuffer, ring));
-    _write.start = _write.end = _write.ring;
-    ZeroMemory(&_read, offsetof(VDIPortBuffer, ring));
-    _read.start = _read.end = _read.ring;
-}
-
-size_t VDIPort::read_ring_size()
-{
-    return (BUF_SIZE + _read.end - _read.start) % BUF_SIZE;
-}
-
-size_t VDIPort::write_ring_free_space()
-{
-    return (BUF_SIZE + _write.start - _write.end - 1) % BUF_SIZE;
-}
-
-size_t VDIPort::ring_write(const void* buf, size_t size)
-{
-    size_t free_size = (BUF_SIZE + _write.start - _write.end - 1) % BUF_SIZE;
-    size_t n;
-
-    if (size > free_size) {
-        size = free_size;
-    }
-    if (_write.end < _write.start) {
-        memcpy(_write.end, buf, size);
-    } else {
-        n = MIN(size, (size_t)(&_write.ring[BUF_SIZE] - _write.end));
-        memcpy(_write.end, buf, n);
-        if (size > n) {
-            memcpy(_write.ring, (uint8_t*)buf + n, size - n);
-        }
-    }
-    _write.end = _write.ring + (_write.end - _write.ring + size) % BUF_SIZE;
-    return size;
-}
-
-size_t VDIPort::read_ring_continuous_remaining_size()
-{
-    DWORD size;
-
-    if (_read.start <= _read.end) {
-        size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end));
-    } else {
-        size = (DWORD)(_read.start - _read.end - 1);
-    }
-    return size;
-}
-
-size_t VDIPort::ring_read(void* buf, size_t size)
-{
-    size_t n;
-    size_t m = 0;
-
-    if (_read.start == _read.end) {
-        return 0;
-    }
-    if (_read.start < _read.end) {
-        n = MIN(size, (size_t)(_read.end - _read.start));
-        memcpy(buf, _read.start, n);
-    } else {
-        n = MIN(size, (size_t)(&_read.ring[BUF_SIZE] - _read.start));
-        memcpy(buf, _read.start, n);
-        if (size > n) {
-            m = MIN(size - n, (size_t)(_read.end - _read.ring));
-            memcpy((uint8_t*)buf + n, _read.ring, m);
-        }
-    }
-    _read.start = _read.ring + (_read.start - _read.ring + n + m) % BUF_SIZE;
-    return n + m;
-}
-
-int VDIPort::handle_error()
-{
-    switch (GetLastError()) {
-    case ERROR_CONNECTION_INVALID:
-        vd_printf("port reset");
-        _write.start = _write.end = _write.ring;
-        _read.start = _read.end = _read.ring;
-        return VDI_PORT_RESET;
-    default:
-        vd_printf("port io failed: %lu", GetLastError());
-        return VDI_PORT_ERROR;
-    }
-}
diff --git a/vdservice/vdi_port.h b/vdservice/vdi_port.h
deleted file mode 100644
index a0fb20e..0000000
--- a/vdservice/vdi_port.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _H_VDI_PORT
-#define _H_VDI_PORT
-
-#include <windows.h>
-#include <stdint.h>
-
-#define MIN(a, b) ((a) > (b) ? (b) : (a))
-
-#define BUF_SIZE    (1024 * 1024)
-
-#define VDI_PORT_BLOCKED    0
-#define VDI_PORT_RESET      -1
-#define VDI_PORT_ERROR      -2
-
-// Ring notes:
-// _end is one after the end of data
-// _start==_end means empty ring
-// _start-1==_end (modulo) means full ring
-// _start-1 is never used
-// ring_write & read on right side of the ring (update _end)
-// ring_read & write from left (update _start)
-
-typedef struct VDIPortBuffer {
-    OVERLAPPED overlap;
-    uint8_t* start;
-    uint8_t* end;
-    bool pending;
-    int bytes;
-    uint8_t ring[BUF_SIZE];
-} VDIPortBuffer;
-
-class VDIPort {
-public:
-    VDIPort();
-    virtual ~VDIPort() {}
-
-    size_t ring_write(const void* buf, size_t size);
-    size_t write_ring_free_space();
-    size_t ring_read(void* buf, size_t size);
-    size_t read_ring_size();
-    size_t read_ring_continuous_remaining_size();
-
-    virtual const char *name() = 0;
-    virtual bool init() = 0;
-    virtual unsigned get_num_events() = 0;
-    virtual void fill_events(HANDLE* handles) = 0;
-    virtual bool handle_event(int event) = 0;
-    virtual int write() = 0;
-    virtual int read() = 0;
-
-protected:
-    int handle_error();
-
-    VDIPortBuffer _write;
-    VDIPortBuffer _read;
-};
-
-#endif
diff --git a/vdservice/virtio_vdi_port.cpp b/vdservice/virtio_vdi_port.cpp
deleted file mode 100644
index be5568a..0000000
--- a/vdservice/virtio_vdi_port.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "stdio.h"
-#include "virtio_vdi_port.h"
-#include "vdlog.h"
-
-#define VIOSERIAL_PORT_PATH                 L"\\\\.\\Global\\com.redhat.spice.0"
-
-// Current limitation of virtio-serial windows driver (RHBZ 617000)
-#define VIOSERIAL_PORT_MAX_WRITE_BYTES      2048
-
-VirtioVDIPort* VirtioVDIPort::_singleton;
-
-VirtioVDIPort::VirtioVDIPort()
-    : VDIPort()
-    , _handle (INVALID_HANDLE_VALUE)
-{
-    _singleton = this;
-}
-
-VirtioVDIPort::~VirtioVDIPort()
-{
-    if (_handle != INVALID_HANDLE_VALUE) {
-        CloseHandle(_handle);
-    }
-    if (_read.overlap.hEvent) {
-        CloseHandle(_read.overlap.hEvent);
-    }
-    if (_write.overlap.hEvent) {
-        CloseHandle(_write.overlap.hEvent);
-    }
-}
-
-void VirtioVDIPort::fill_events(HANDLE* handles) {
-    handles[VIRTIO_VDI_PORT_EVENT_WRITE] = _write.overlap.hEvent;
-    handles[VIRTIO_VDI_PORT_EVENT_READ] = _read.overlap.hEvent;
-}
-
-bool VirtioVDIPort::handle_event(int event) {
-    bool ret;
-
-    switch (event) {
-        case VIRTIO_VDI_PORT_EVENT_WRITE:
-            ret = write_completion();
-            break;
-        case VIRTIO_VDI_PORT_EVENT_READ:
-            ret = read_completion();
-            break;
-        default:
-            vd_printf("ERROR: unexpected event %d", event);
-            ret = false;
-    }
-    return ret;
-}
-
-bool VirtioVDIPort::init()
-{
-    _handle = CreateFile(VIOSERIAL_PORT_PATH, GENERIC_READ | GENERIC_WRITE , 0, NULL,
-                         OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
-    if (_handle == INVALID_HANDLE_VALUE) {
-        vd_printf("CreateFile() %ls failed: %lu", VIOSERIAL_PORT_PATH, GetLastError());
-        return false;
-    }
-    _write.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (_write.overlap.hEvent == NULL) {
-        vd_printf("CreateEvent() failed: %lu", GetLastError());
-        return false;
-    }
-    _read.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (_read.overlap.hEvent == NULL) {
-        vd_printf("CreateEvent() failed: %lu", GetLastError());
-        return false;
-    }
-    return true;
-}
-
-int VirtioVDIPort::write()
-{
-    int size;
-    int ret;
-
-    //FIXME: return VDI_PORT_NO_DATA
-    if (_write.start == _write.end) {
-        return 0;
-    }
-    if (!_write.pending) {
-        if (_write.start < _write.end) {
-            size = (int)(_write.end - _write.start);
-        } else {
-            size = (int)(&_write.ring[BUF_SIZE] - _write.start);
-        }
-        size = MIN(size, VIOSERIAL_PORT_MAX_WRITE_BYTES);
-        _write.pending = true;
-        if (WriteFile(_handle, _write.start, size, NULL, &_write.overlap)) {
-            write_completion();
-        } if (GetLastError() != ERROR_IO_PENDING) {
-            return handle_error();
-        }
-    }
-    ret = _write.bytes;
-    _write.bytes = 0;
-    return ret;
-}
-
-bool VirtioVDIPort::write_completion()
-{
-    DWORD bytes;
-
-    if (!_write.pending) {
-        return true;
-    }
-    if (!GetOverlappedResult(_handle, &_write.overlap, &bytes, FALSE)) {
-        vd_printf("GetOverlappedResult failed: %lu", GetLastError());
-        return false;
-    }
-    _write.start = _write.ring + (_write.start - _write.ring + bytes) % BUF_SIZE;
-    _write.bytes = bytes;
-    _write.pending = false;
-    return true;
-}
-
-int VirtioVDIPort::read()
-{
-    int size;
-    int ret;
-
-    if (!_read.pending) {
-        //FIXME: read_ring_continuous_remaining_size? return VDI_PORT_BUFFER_FULL
-        if ((_read.end - _read.ring + 1) % BUF_SIZE == _read.start - _read.ring) {
-            vd_printf("DEBUG: buffer full");
-            return 0;
-        }
-        if (_read.start == _read.end) {
-            _read.start = _read.end = _read.ring;
-        }
-        if (_read.start <= _read.end) {
-            size = MIN(BUF_SIZE - 1, (int)(&_read.ring[BUF_SIZE] - _read.end));
-        } else {
-            size = (int)(_read.start - _read.end - 1);
-        }
-        _read.pending = true;
-        if (ReadFile(_handle, _read.end, size, NULL, &_read.overlap)) {
-            read_completion();
-        } else if (GetLastError() != ERROR_IO_PENDING) {
-            return handle_error();
-        }
-    }
-    ret = _read.bytes;
-    _read.bytes = 0;
-    return ret;
-}
-
-bool VirtioVDIPort::read_completion()
-{
-    DWORD bytes;
-
-    if (!GetOverlappedResult(_handle, &_read.overlap, &bytes, FALSE)) {
-        DWORD err = GetLastError();
-
-        if (err == ERROR_OPERATION_ABORTED || err == ERROR_NO_SYSTEM_RESOURCES) {
-            _read.pending = false;
-            return true;
-        } else if (err != ERROR_MORE_DATA) {
-            vd_printf("GetOverlappedResult failed: %lu", err);
-            return false;
-        }
-    }
-    _read.end = _read.ring + (_read.end - _read.ring + bytes) % BUF_SIZE;
-    _read.bytes = bytes;
-    _read.pending = false;
-    return true;
-}
diff --git a/vdservice/virtio_vdi_port.h b/vdservice/virtio_vdi_port.h
deleted file mode 100644
index d72edf4..0000000
--- a/vdservice/virtio_vdi_port.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef _H_VIRTIO_VDI_PORT
-#define _H_VIRTIO_VDI_PORT
-
-#include "vdi_port.h"
-
-enum {
-    VIRTIO_VDI_PORT_EVENT_WRITE=0,
-    VIRTIO_VDI_PORT_EVENT_READ,
-    VIRTIO_VDI_PORT_EVENT_COUNT
-};
-
-class VirtioVDIPort : public VDIPort {
-public:
-    VirtioVDIPort();
-    ~VirtioVDIPort();
-    virtual const char *name() { return "VirtioVDIPort"; }
-    virtual bool init();
-    virtual unsigned get_num_events() { return VIRTIO_VDI_PORT_EVENT_COUNT; }
-    virtual void fill_events(HANDLE* handles);
-    virtual bool handle_event(int event);
-    virtual int write();
-    virtual int read();
-
-private:
-    bool write_completion();
-    bool read_completion();
-
-private:
-    static VirtioVDIPort* _singleton;
-    HANDLE _handle;
-};
-
-#endif //_H_VIRTIO_VDI_PORT
commit 9f44263959e8bd2dfe02d3d671570f9abafe03cb
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Tue Nov 6 12:24:45 2012 +0200

    vdservice: remove virtio-serial & pipe usage

diff --git a/vdservice/vdservice.cpp b/vdservice/vdservice.cpp
index 2b925fd..8f12317 100644
--- a/vdservice/vdservice.cpp
+++ b/vdservice/vdservice.cpp
@@ -18,13 +18,10 @@
 #include <windows.h>
 #include <winternl.h>
 #include <wtsapi32.h>
-#include <userenv.h>
 #include <stdio.h>
 #include <tlhelp32.h>
 #include <queue>
 #include "vdcommon.h"
-#include "virtio_vdi_port.h"
-#include "pci_vdi_port.h"
 
 //#define DEBUG_VDSERVICE
 
@@ -45,21 +42,16 @@
 // This enum simplifies WaitForMultipleEvents for static
 // events, that is handles that are guranteed non NULL.
 // It doesn't include:
-// VirtioVDIPort Handles - these are filled by an interface because
-//  of variable handle number.
 // VDAgent handle - this can be 1 or 0 (NULL or not), so it is also added at
 //  the end of VDService::_events
 enum {
-    VD_EVENT_PIPE_READ = 0,
-    VD_EVENT_PIPE_WRITE,
-    VD_EVENT_CONTROL,
+    VD_EVENT_CONTROL = 0,
     VD_STATIC_EVENTS_COUNT // Must be last
 };
 
 enum {
     VD_CONTROL_IDLE = 0,
     VD_CONTROL_STOP,
-    VD_CONTROL_LOGON,
     VD_CONTROL_RESTART_AGENT,
 };
 
@@ -80,16 +72,8 @@ private:
     static DWORD WINAPI control_handler(DWORD control, DWORD event_type,
                                         LPVOID event_data, LPVOID context);
     static VOID WINAPI main(DWORD argc, TCHAR * argv[]);
-    bool init_vdi_port();
     void set_control_event(int control_command);
     void handle_control_event();
-    void pipe_write_completion();
-    void pipe_read_completion();
-    void write_agent_control(uint32_t type, uint32_t opaque);
-    void read_pipe();
-    void handle_pipe_data(DWORD bytes);
-    void handle_port_data();
-    bool handle_agent_control(VDPipeMessage* msg);
     bool restart_agent(bool normal_restart);
     bool launch_agent();
     bool kill_agent();
@@ -110,22 +94,14 @@ private:
     HANDLE _control_event;
     HANDLE* _events;
     TCHAR _agent_path[MAX_PATH];
-    VDIPort* _vdi_port;
-    VDPipeState _pipe_state;
     VDControlQueue _control_queue;
     mutex_t _control_mutex;
     mutex_t _agent_mutex;
     uint32_t _connection_id;
     DWORD _session_id;
-    DWORD _chunk_port;
-    DWORD _chunk_size;
     DWORD _last_agent_restart_time;
     int _agent_restarts;
     int _system_version;
-    bool _pipe_connected;
-    bool _pending_reset;
-    bool _pending_write;
-    bool _pending_read;
     bool _agent_alive;
     bool _running;
     VDLog* _log;
@@ -169,28 +145,18 @@ int supported_system_version()
 VDService::VDService()
     : _status_handle (0)
     , _events (NULL)
-    , _vdi_port (NULL)
     , _connection_id (0)
     , _session_id (0)
-    , _chunk_port (0)
-    , _chunk_size (0)
     , _last_agent_restart_time (0)
     , _agent_restarts (0)
-    , _pipe_connected (false)
-    , _pending_reset (false)
-    , _pending_write (false)
-    , _pending_read (false)
     , _agent_alive (false)
     , _running (false)
     , _log (NULL)
     , _events_count(0)
 {
     ZeroMemory(&_agent_proc_info, sizeof(_agent_proc_info));
-    ZeroMemory(&_pipe_state, sizeof(_pipe_state));
     _system_version = supported_system_version();
     _control_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-    _pipe_state.write.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-    _pipe_state.read.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
     _agent_path[0] = wchar_t('\0');
     MUTEX_INIT(_agent_mutex);
     MUTEX_INIT(_control_mutex);
@@ -199,8 +165,6 @@ VDService::VDService()
 
 VDService::~VDService()
 {
-    CloseHandle(_pipe_state.read.overlap.hEvent);
-    CloseHandle(_pipe_state.write.overlap.hEvent);
     CloseHandle(_control_event);
     delete _events;
     delete _log;
@@ -320,14 +284,10 @@ void VDService::handle_control_event()
     while (_control_queue.size()) {
         int control_command = _control_queue.front();
         _control_queue.pop();
-        vd_printf("Control command %d", control_command);
         switch (control_command) {
         case VD_CONTROL_STOP:
             _running = false;
             break;
-        case VD_CONTROL_LOGON:
-            write_agent_control(VD_AGENT_SESSION_LOGON, 0);
-            break;
         case VD_CONTROL_RESTART_AGENT:
             _running = restart_agent(true);
             break;
@@ -361,13 +321,9 @@ DWORD WINAPI VDService::control_handler(DWORD control, DWORD event_type, LPVOID
         DWORD session_id = ((WTSSESSION_NOTIFICATION*)event_data)->dwSessionId;
         vd_printf("Session %lu %s", session_id, session_events[event_type]);
         SetServiceStatus(s->_status_handle, &s->_status);
-        if (s->_system_version != SYS_VER_UNSUPPORTED) {
-            if (event_type == WTS_CONSOLE_CONNECT) {
-                s->_session_id = session_id;
-                s->set_control_event(VD_CONTROL_RESTART_AGENT);
-            } else if (event_type == WTS_SESSION_LOGON) {
-                s->set_control_event(VD_CONTROL_LOGON);
-            }
+        if (event_type == WTS_CONSOLE_CONNECT) {
+            s->_session_id = session_id;
+            s->set_control_event(VD_CONTROL_RESTART_AGENT);
         }
         break;
     }
@@ -445,57 +401,12 @@ VOID WINAPI VDService::main(DWORD argc, TCHAR* argv[])
     vd_printf("***Service stopped***");
 }
 
-VDIPort *create_virtio_vdi_port()
-{
-    return new VirtioVDIPort();
-}
-
-VDIPort *create_pci_vdi_port()
-{
-    return new PCIVDIPort();
-}
-
-bool VDService::init_vdi_port()
-{
-    VDIPort* (*creators[])(void) = { create_virtio_vdi_port, create_pci_vdi_port };
-
-    for (unsigned int i = 0 ; i < sizeof(creators)/sizeof(creators[0]); ++i) {
-        _vdi_port = creators[i]();
-        if (_vdi_port->init()) {
-            return true;
-        }
-        delete _vdi_port;
-    }
-    _vdi_port = NULL;
-    return false;
-}
-
 bool VDService::execute()
 {
-    SECURITY_ATTRIBUTES sec_attr;
-    SECURITY_DESCRIPTOR* sec_desr;
-    HANDLE pipe;
     INT* con_state = NULL;
     bool con_state_active = false;
     DWORD bytes;
 
-    sec_desr = (SECURITY_DESCRIPTOR*)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
-    InitializeSecurityDescriptor(sec_desr, SECURITY_DESCRIPTOR_REVISION);
-    SetSecurityDescriptorDacl(sec_desr, TRUE, (PACL)NULL, FALSE);
-    sec_attr.nLength = sizeof(sec_attr);
-    sec_attr.bInheritHandle = TRUE;
-    sec_attr.lpSecurityDescriptor = sec_desr;
-    pipe = CreateNamedPipe(VD_SERVICE_PIPE_NAME, PIPE_ACCESS_DUPLEX |
-                           FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
-                           PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
-                           PIPE_UNLIMITED_INSTANCES, BUF_SIZE, BUF_SIZE,
-                           VD_AGENT_TIMEOUT, &sec_attr);
-    LocalFree(sec_desr);
-    if (pipe == INVALID_HANDLE_VALUE) {
-        vd_printf("CreatePipe() failed: %lu", GetLastError());
-        return false;
-    }
-    _pipe_state.pipe = pipe;
     _session_id = WTSGetActiveConsoleSessionId();
     if (_session_id == 0xFFFFFFFF) {
         vd_printf("WTSGetActiveConsoleSessionId() failed");
@@ -517,101 +428,52 @@ bool VDService::execute()
         if (_running) {
             vd_printf("Failed launching vdagent instance, waiting for session connection");
         }
-        while (_running && !_pipe_connected) {
+        while (_running) {
             if (WaitForSingleObject(_control_event, INFINITE) == WAIT_OBJECT_0) {
                 handle_control_event();
             }
         }
     }
-    if (_running && !init_vdi_port()) {
-        vd_printf("Failed to create VDIPort instance");
-        _running = false;
-    }
     if (!_running) {
-        CloseHandle(pipe);
         return false;
     }
-    vd_printf("created %s", _vdi_port->name());
-    _events_count = VD_STATIC_EVENTS_COUNT + _vdi_port->get_num_events() + 1 /*for agent*/;
+    _events_count = VD_STATIC_EVENTS_COUNT + 1 /*for agent*/;
     _events = new HANDLE[_events_count];
     ZeroMemory(_events, _events_count);
-    vd_printf("Connected to server");
-    _events[VD_EVENT_PIPE_READ] = _pipe_state.read.overlap.hEvent;
-    _events[VD_EVENT_PIPE_WRITE] = _pipe_state.write.overlap.hEvent;
     _events[VD_EVENT_CONTROL] = _control_event;
-    _vdi_port->fill_events(&_events[VD_STATIC_EVENTS_COUNT]);
-    _chunk_size = _chunk_port = 0;
-    read_pipe();
     while (_running) {
-        int cont_read = _vdi_port->read();
-        int cont_write = _vdi_port->write();
-        bool cont = false;
-
-        if (cont_read >= 0 && cont_write >= 0) {
-            cont = cont_read || cont_write;
-        } else if (cont_read == VDI_PORT_ERROR || cont_write == VDI_PORT_ERROR) {
-            vd_printf("VDI Port error, read %d write %d", cont_read, cont_write);
-            _running = false;
-        } else if (cont_read == VDI_PORT_RESET || cont_write == VDI_PORT_RESET) {
-            vd_printf("VDI Port reset, read %d write %d", cont_read, cont_write);
-            _chunk_size = _chunk_port = 0;
-            write_agent_control(VD_AGENT_RESET, ++_connection_id);
-            _pending_reset = true;
-        }
-        if (cont) {
-            handle_port_data();
-        }
-        if (cont_write) {
-            handle_pipe_data(0);
-        }
-        if (_running && (!cont || _pending_read || _pending_write)) {
-            unsigned actual_events = fill_agent_event();
-            DWORD wait_ret = WaitForMultipleObjects(actual_events, _events, FALSE,
-                                                              cont ? 0 : INFINITE);
-            switch (wait_ret) {
-            case WAIT_OBJECT_0 + VD_EVENT_PIPE_READ:
-                pipe_read_completion();
-                break;
-            case WAIT_OBJECT_0 + VD_EVENT_PIPE_WRITE:
-                pipe_write_completion();
-                break;
-            case WAIT_OBJECT_0 + VD_EVENT_CONTROL:
-                handle_control_event();
-                break;
-            case WAIT_TIMEOUT:
-                break;
-            default:
-                if (wait_ret == WAIT_OBJECT_0 + _events_count - 1) {
-                    vd_printf("Agent killed");
-                    if (_system_version == SYS_VER_WIN_XP_CLASS) {
-                        restart_agent(false);
-                    } else if (_system_version == SYS_VER_WIN_7_CLASS) {
-                        kill_agent();
-                        // Assume agent was killed due to console disconnect, and wait for agent
-                        // normal restart due to console connect. If the agent is not alive yet,
-                        // it was killed manually (or crashed), so let's restart it.
-                        if (WaitForSingleObject(_control_event, VD_AGENT_RESTART_INTERVAL) ==
-                                WAIT_OBJECT_0) {
-                            handle_control_event();
-                        }
-                        if (_running && !_agent_alive) {
-                            restart_agent(false);
-                        }
-                    }
-                } else {
-                    int vdi_event = wait_ret - VD_STATIC_EVENTS_COUNT - WAIT_OBJECT_0;
-                    if (vdi_event >= 0 && vdi_event < _vdi_port->get_num_events()) {
-                        _running = _vdi_port->handle_event(vdi_event);
-                    } else {
-                        vd_printf("WaitForMultipleObjects failed %lu", GetLastError());
-                        _running = false;
-                    }
+        unsigned actual_events = fill_agent_event();
+        DWORD wait_ret = WaitForMultipleObjects(actual_events, _events, FALSE, INFINITE);
+        switch (wait_ret) {
+        case WAIT_OBJECT_0 + VD_EVENT_CONTROL:
+            handle_control_event();
+            break;
+        case WAIT_OBJECT_0 + VD_STATIC_EVENTS_COUNT:
+            vd_printf("Agent killed");
+            if (_system_version == SYS_VER_WIN_XP_CLASS) {
+                restart_agent(false);
+            } else if (_system_version == SYS_VER_WIN_7_CLASS) {
+                kill_agent();
+                // Assume agent was killed due to console disconnect, and wait for agent
+                // normal restart due to console connect. If the agent is not alive yet,
+                // it was killed manually (or crashed), so let's restart it.
+                if (WaitForSingleObject(_control_event, VD_AGENT_RESTART_INTERVAL) ==
+                        WAIT_OBJECT_0) {
+                    handle_control_event();
+                }
+                if (_running && !_agent_alive) {
+                    restart_agent(false);
                 }
             }
+            break;
+        case WAIT_TIMEOUT:
+            break;
+        default:
+            vd_printf("WaitForMultipleObjects failed %lu", GetLastError());
+            _running = false;
         }
     }
-    delete _vdi_port;
-    CloseHandle(pipe);
+    kill_agent();
     return true;
 }
 
@@ -857,7 +719,6 @@ BOOL create_process_as_user(IN DWORD session_id, IN LPCWSTR application_name,
 bool VDService::launch_agent()
 {
     STARTUPINFO startup_info;
-    OVERLAPPED overlap;
     BOOL ret = FALSE;
 
     ZeroMemory(&startup_info, sizeof(startup_info));
@@ -893,34 +754,7 @@ bool VDService::launch_agent()
         return false;
     }
     _agent_alive = true;
-    if (_pipe_connected) {
-        vd_printf("Pipe already connected");
-        return false;
-    }
-    vd_printf("Wait for vdagent to connect");
-    ZeroMemory(&overlap, sizeof(overlap));
-    overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-    DWORD err = (ConnectNamedPipe(_pipe_state.pipe, &overlap) ? 0 : GetLastError());
-    if (err == ERROR_IO_PENDING) {
-        HANDLE wait_handles[2] = {overlap.hEvent, _agent_proc_info.hProcess};
-        DWORD wait_ret = WaitForMultipleObjects(2, wait_handles, FALSE, VD_AGENT_TIMEOUT);
-        if (wait_ret != WAIT_OBJECT_0) {
-            _agent_proc_info.hProcess = 0;
-            vd_printf("Failed waiting for vdagent connection: %lu error: %lu", wait_ret,
-                wait_ret == WAIT_FAILED ? GetLastError() : 0);
-            ret = FALSE;
-        }
-    } else if (err != 0 && err != ERROR_PIPE_CONNECTED) {
-        vd_printf("ConnectNamedPipe() failed: %lu", err);
-        ret = FALSE;
-    }
-    if (ret) {
-        vd_printf("Pipe connected by vdagent");
-        _pipe_connected = true;
-        _pending_reset = false;
-    }
-    CloseHandle(overlap.hEvent);
-    return !!ret;
+    return true;
 }
 
 bool VDService::kill_agent()
@@ -936,16 +770,12 @@ bool VDService::kill_agent()
     _agent_alive = false;
     proc_handle = _agent_proc_info.hProcess;
     _agent_proc_info.hProcess = 0;
-    if (_pipe_connected) {
-        _pipe_connected = false;
-        DisconnectNamedPipe(_pipe_state.pipe);
-    }
+    TerminateProcess(proc_handle, 0);
     if (GetProcessId(proc_handle)) {
         wait_ret = WaitForSingleObject(proc_handle, VD_AGENT_TIMEOUT);
         switch (wait_ret) {
         case WAIT_OBJECT_0:
             if (GetExitCodeProcess(proc_handle, &exit_code)) {
-                vd_printf("vdagent exit code %lu", exit_code);
                 ret = (exit_code != STILL_ACTIVE);
             } else {
                 vd_printf("GetExitCodeProcess() failed: %lu", GetLastError());
@@ -984,9 +814,6 @@ bool VDService::restart_agent(bool normal_restart)
         }
         _last_agent_restart_time = time;
         ret = true;
-        if (_vdi_port) {
-            read_pipe();
-        }
     }
     MUTEX_UNLOCK(_agent_mutex);
     return ret;
@@ -998,232 +825,6 @@ void VDService::stop()
     set_control_event(VD_CONTROL_STOP);
 }
 
-void VDService::pipe_write_completion()
-{
-    VDPipeState* ps = &this->_pipe_state;
-    DWORD bytes;
-
-    if (!_running) {
-        return;
-    }
-    if (_pending_write) {
-        if (GetOverlappedResult(_pipe_state.pipe, &_pipe_state.write.overlap, &bytes, FALSE)) {
-            ps->write.start += bytes;
-            if (ps->write.start == ps->write.end) {
-                ps->write.start = ps->write.end = 0;
-            }
-        } else if (GetLastError() == ERROR_IO_PENDING){
-            vd_printf("Overlapped write is pending");
-            return;
-        } else {
-            vd_printf("GetOverlappedResult() failed : %lu", GetLastError());
-        }
-        _pending_write = false;
-    }
-
-    if (ps->write.start < ps->write.end) {
-        _pending_write = true;
-        if (!WriteFile(ps->pipe, ps->write.data + ps->write.start,
-                       ps->write.end - ps->write.start, NULL, &_pipe_state.write.overlap)) {
-            vd_printf("vdagent disconnected (%lu)", GetLastError());
-            _pending_write = false;
-            _pipe_connected = false;
-            DisconnectNamedPipe(_pipe_state.pipe);
-        }
-    } else {
-        _pending_write = false;
-    }
-}
-
-void VDService::pipe_read_completion()
-{
-    DWORD bytes = 0;
-    DWORD err = ERROR_SUCCESS;
-
-    if (!_pipe_connected || !_pending_read) {
-        return;
-    }
-    _pending_read = false;
-    if (!GetOverlappedResult(_pipe_state.pipe, &_pipe_state.read.overlap, &bytes, FALSE)) {
-        err = GetLastError();
-    }
-    switch (err) {
-    case ERROR_SUCCESS:
-    case ERROR_MORE_DATA:
-        handle_pipe_data(bytes);
-        read_pipe();
-        break;
-    case ERROR_IO_INCOMPLETE:
-        break;
-    default:
-        vd_printf("vdagent disconnected (%lu)", err);
-        _pipe_connected = false;
-        DisconnectNamedPipe(_pipe_state.pipe);
-    }
-}
-
-void VDService::read_pipe()
-{
-    VDPipeState* ps = &_pipe_state;
-    DWORD bytes;
-
-    if (ps->read.end < sizeof(ps->read.data)) {
-        _pending_read = true;
-        if (ReadFile(ps->pipe, ps->read.data + ps->read.end, sizeof(ps->read.data) - ps->read.end,
-                     &bytes, &ps->read.overlap) || GetLastError() == ERROR_MORE_DATA) {
-            _pending_read = false;
-            handle_pipe_data(bytes);
-            read_pipe();
-        } else if (GetLastError() != ERROR_IO_PENDING) {
-            vd_printf("vdagent disconnected (%lu)", GetLastError());
-            _pending_read = false;
-            _pipe_connected = false;
-            DisconnectNamedPipe(_pipe_state.pipe);
-        }
-    } else {
-        _pending_read = false;
-    }
-}
-
-//FIXME: division to max size chunks should be here, not in the agent
-void VDService::handle_pipe_data(DWORD bytes)
-{
-    VDPipeState* ps = &_pipe_state;
-    DWORD read_size;
-
-    if (bytes) {
-        _pending_read = false;
-    }
-    if (!_running) {
-        return;
-    }
-    ps->read.end += bytes;
-    while (_running && (read_size = ps->read.end - ps->read.start) >= sizeof(VDPipeMessage)) {
-        VDPipeMessage* pipe_msg = (VDPipeMessage*)&ps->read.data[ps->read.start];
-        if (pipe_msg->type != VD_AGENT_COMMAND) {
-            handle_agent_control(pipe_msg);
-            ps->read.start += sizeof(VDPipeMessage);
-            continue;
-        }
-        if (read_size < sizeof(VDPipeMessage) + pipe_msg->size) {
-            break;
-        }
-        if (_vdi_port->write_ring_free_space() < sizeof(VDIChunkHeader) + pipe_msg->size) {
-            //vd_printf("DEBUG: no space in write ring %u", _vdi_port->write_ring_free_space());
-            break;
-        }
-        if (!_pending_reset) {
-            VDIChunkHeader chunk;
-            chunk.port = pipe_msg->opaque;
-            chunk.size = pipe_msg->size;
-            if (_vdi_port->ring_write(&chunk, sizeof(chunk)) != sizeof(chunk) ||
-                    _vdi_port->ring_write(pipe_msg->data, chunk.size) != chunk.size) {
-                vd_printf("ring_write failed");
-                _running = false;
-                return;
-            }
-        }
-        ps->read.start += (sizeof(VDPipeMessage) + pipe_msg->size);
-    }
-    if (ps->read.start == ps->read.end && !_pending_read) {
-        DWORD prev_read_end = ps->read.end;
-        ps->read.start = ps->read.end = 0;
-        if (prev_read_end == sizeof(ps->read.data)) {
-            read_pipe();
-        }
-    }
-}
-
-void VDService::handle_port_data()
-{
-    VDPipeMessage* pipe_msg;
-    VDIChunkHeader chunk;
-    int chunks_count = 0;
-    DWORD count = 0;
-
-    while (_running) {
-        if (!_chunk_size && _vdi_port->read_ring_size() >= sizeof(chunk)) {
-            if (_vdi_port->ring_read(&chunk, sizeof(chunk)) != sizeof(chunk)) {
-                vd_printf("ring_read of chunk header failed");
-                _running = false;
-                break;
-            }
-            count = sizeof(VDPipeMessage) + chunk.size;
-            if (_pipe_state.write.end + count > sizeof(_pipe_state.write.data)) {
-                vd_printf("chunk is too large, size %u port %u", chunk.size, chunk.port);
-                _running = false;
-                break;
-            }
-            _chunk_size = chunk.size;
-            _chunk_port = chunk.port;
-        }
-        if (_chunk_size && _vdi_port->read_ring_size() >= _chunk_size) {
-            count = sizeof(VDPipeMessage) + _chunk_size;
-            ASSERT(_pipe_state.write.end + count <= sizeof(_pipe_state.write.data));
-            pipe_msg = (VDPipeMessage*)&_pipe_state.write.data[_pipe_state.write.end];
-            if (_vdi_port->ring_read(pipe_msg->data, _chunk_size) != _chunk_size) {
-                vd_printf("ring_read of chunk data failed");
-                _running = false;
-                break;
-            }
-            if (_pipe_connected) {
-                pipe_msg->type = VD_AGENT_COMMAND;
-                pipe_msg->opaque = _chunk_port;
-                pipe_msg->size = _chunk_size;
-                _pipe_state.write.end += count;
-                chunks_count++;
-            } else {
-                _pipe_state.write.start = _pipe_state.write.end = 0;
-            }
-            _chunk_size = 0;
-            _chunk_port = 0;
-        } else {
-            break;
-        }
-    }
-    if (_pipe_connected && chunks_count && !_pending_write) {
-        pipe_write_completion();
-    }
-}
-
-bool VDService::handle_agent_control(VDPipeMessage* msg)
-{
-    switch (msg->type) {
-    case VD_AGENT_RESET_ACK: {
-        if (msg->opaque != _connection_id) {
-            vd_printf("Agent reset ack mismatch %u %u", msg->opaque, _connection_id);
-            break;
-        }
-        vd_printf("Agent reset ack");
-        _pending_reset = false;
-        break;
-    }
-    default:
-        vd_printf("Unsupported control %u %u", msg->type, msg->opaque);
-        return false;
-    }
-    return true;
-}
-
-void VDService::write_agent_control(uint32_t type, uint32_t opaque)
-{
-    if (!_pipe_connected) {
-        return;
-    }
-    if (_pipe_state.write.end + sizeof(VDPipeMessage) > sizeof(_pipe_state.write.data)) {
-        vd_printf("msg is too large");
-        _running = false;
-        return;
-    }
-    VDPipeMessage* msg = (VDPipeMessage*)&_pipe_state.write.data[_pipe_state.write.end];
-    msg->type = type;
-    msg->opaque = opaque;
-    _pipe_state.write.end += sizeof(VDPipeMessage);
-    if (!_pending_write) {
-        pipe_write_completion();
-    }
-}
-
 #ifdef __GNUC__
 #undef _tmain
 #ifdef UNICODE
diff --git a/vdservice/vdservice.vcproj b/vdservice/vdservice.vcproj
index 8ec0505..45af4c5 100644
--- a/vdservice/vdservice.vcproj
+++ b/vdservice/vdservice.vcproj
@@ -335,10 +335,6 @@
 			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
 			>
 			<File
-				RelativePath=".\pci_vdi_port.h"
-				>
-			</File>
-			<File
 				RelativePath=".\resource.h"
 				>
 			</File>
@@ -347,17 +343,9 @@
 				>
 			</File>
 			<File
-				RelativePath=".\vdi_port.h"
-				>
-			</File>
-			<File
 				RelativePath="..\common\vdlog.h"
 				>
 			</File>
-			<File
-				RelativePath=".\virtio_vdi_port.h"
-				>
-			</File>
 		</Filter>
 		<Filter
 			Name="Resource Files"
@@ -375,14 +363,6 @@
 			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
 			>
 			<File
-				RelativePath=".\pci_vdi_port.cpp"
-				>
-			</File>
-			<File
-				RelativePath=".\vdi_port.cpp"
-				>
-			</File>
-			<File
 				RelativePath="..\common\vdlog.cpp"
 				>
 			</File>
@@ -390,10 +370,6 @@
 				RelativePath=".\vdservice.cpp"
 				>
 			</File>
-			<File
-				RelativePath=".\virtio_vdi_port.cpp"
-				>
-			</File>
 		</Filter>
 	</Files>
 	<Globals>


More information about the Spice-commits mailing list