--- vdagent/vdagent.cpp | 467 +++++++++++++++++++++++------------------------- vdagent/vdagent.vcproj | 32 +++- 2 files changed, 256 insertions(+), 243 deletions(-) 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" -- 1.7.4.1 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel