make VDIPort an abstract class. rename old VDIPort VirtioVDIPort. h file for virtio_vdi_port will be introduced later. --- vdservice/vdi_port.cpp | 242 ----------------------------------------- vdservice/vdi_port.h | 44 +++++--- vdservice/vdservice.cpp | 4 +- vdservice/virtio_vdi_port.cpp | 242 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 274 insertions(+), 258 deletions(-) delete mode 100644 vdservice/vdi_port.cpp create mode 100644 vdservice/virtio_vdi_port.cpp
diff --git a/vdservice/vdi_port.cpp b/vdservice/vdi_port.cpp deleted file mode 100644 index f4dfaeb..0000000 --- a/vdservice/vdi_port.cpp +++ /dev/null @@ -1,242 +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 "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 - -#define MIN(a, b) ((a) > (b) ? (b) : (a)) - -VDIPort* VDIPort::_singleton; - -VDIPort::VDIPort() - : _handle (INVALID_HANDLE_VALUE) -{ - ZeroMemory(&_write, offsetof(VDIPortBuffer, ring)); - _write.start = _write.end = _write.ring; - ZeroMemory(&_read, offsetof(VDIPortBuffer, ring)); - _read.start = _read.end = _read.ring; - _singleton = this; -} - -VDIPort::~VDIPort() -{ - if (_handle != INVALID_HANDLE_VALUE) { - CloseHandle(_handle); - } - if (_read.overlap.hEvent) { - CloseHandle(_read.overlap.hEvent); - } - if (_write.overlap.hEvent) { - CloseHandle(_write.overlap.hEvent); - } -} - -bool VDIPort::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() %s failed: %u", VIOSERIAL_PORT_PATH, GetLastError()); - return false; - } - _write.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (_write.overlap.hEvent == NULL) { - vd_printf("CreateEvent() failed: %u", GetLastError()); - return false; - } - _read.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (_read.overlap.hEvent == NULL) { - vd_printf("CreateEvent() failed: %u", GetLastError()); - return false; - } - return true; -} - -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; -} - -int VDIPort::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; -} - -void VDIPort::write_completion() -{ - DWORD bytes; - - if (!_write.pending) { - return; - } - if (!GetOverlappedResult(_handle, &_write.overlap, &bytes, FALSE)) { - vd_printf("GetOverlappedResult failed: %u", GetLastError()); - return; - } - _write.start = _write.ring + (_write.start - _write.ring + bytes) % BUF_SIZE; - _write.bytes = bytes; - _write.pending = false; -} - -size_t VDIPort::read_ring_size() -{ - return (BUF_SIZE + _read.end - _read.start) % BUF_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::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; -} - -void VDIPort::read_completion() -{ - DWORD bytes; - - if (!GetOverlappedResult(_handle, &_read.overlap, &bytes, FALSE) && - GetLastError() != ERROR_MORE_DATA) { - vd_printf("GetOverlappedResult failed: %u", GetLastError()); - return; - } - _read.end = _read.ring + (_read.end - _read.ring + bytes) % BUF_SIZE; - _read.bytes = bytes; - _read.pending = false; -} - -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: %u", GetLastError()); - return VDI_PORT_ERROR; - } -} diff --git a/vdservice/vdi_port.h b/vdservice/vdi_port.h index 8e057bb..2d2b2d2 100644 --- a/vdservice/vdi_port.h +++ b/vdservice/vdi_port.h @@ -38,27 +38,43 @@ typedef struct VDIPortBuffer { class VDIPort { public: - VDIPort(); - ~VDIPort(); - bool init(); - 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(); - unsigned get_num_events() { return 2; } - void fill_events(HANDLE *handle) { + virtual ~VDIPort() {} + virtual bool init() = 0; + virtual size_t ring_write(const void* buf, size_t size) = 0; + virtual size_t write_ring_free_space() = 0; + virtual size_t ring_read(void* buf, size_t size) = 0; + virtual size_t read_ring_size() = 0; + virtual size_t read_ring_continuous_remaining_size() = 0; + virtual unsigned get_num_events() = 0; + virtual void fill_events(HANDLE *handle) = 0; + virtual void handle_event(int event) = 0; + virtual int write() = 0; + virtual int read() = 0; +}; + +class VirtioVDIPort : public VDIPort { +public: + VirtioVDIPort(); + ~VirtioVDIPort(); + virtual bool init(); + virtual size_t ring_write(const void* buf, size_t size); + virtual size_t write_ring_free_space(); + virtual size_t ring_read(void* buf, size_t size); + virtual size_t read_ring_size(); + virtual size_t read_ring_continuous_remaining_size(); + virtual unsigned get_num_events() { return 2; } + virtual void fill_events(HANDLE *handle) { handle[0] = _write.overlap.hEvent; handle[1] = _read.overlap.hEvent; } - void handle_event(int event) { + virtual void handle_event(int event) { switch (event) { case 0: write_completion(); break; case 1: read_completion(); break; } } - int write(); - int read(); + virtual int write(); + virtual int read(); private: void write_completion(); @@ -66,7 +82,7 @@ private: int handle_error(); private: - static VDIPort* _singleton; + static VirtioVDIPort* _singleton; HANDLE _handle; VDIPortBuffer _write; VDIPortBuffer _read; diff --git a/vdservice/vdservice.cpp b/vdservice/vdservice.cpp index 72882ea..4c7785b 100644 --- a/vdservice/vdservice.cpp +++ b/vdservice/vdservice.cpp @@ -43,7 +43,7 @@ // This enum simplifies WaitForMultipleEvents for static // events, that is handles that are guranteed non NULL. // It doesn't include: -// VDIPort Handles - these are filled by an interface because +// 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 @@ -434,7 +434,7 @@ bool VDService::execute() CloseHandle(pipe); return false; } - _vdi_port = new VDIPort(); + _vdi_port = new VirtioVDIPort(); if (!_vdi_port->init()) { delete _vdi_port; CloseHandle(pipe); diff --git a/vdservice/virtio_vdi_port.cpp b/vdservice/virtio_vdi_port.cpp new file mode 100644 index 0000000..8a7cf19 --- /dev/null +++ b/vdservice/virtio_vdi_port.cpp @@ -0,0 +1,242 @@ +/* + 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 "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 + +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +VirtioVDIPort* VirtioVDIPort::_singleton; + +VirtioVDIPort::VirtioVDIPort() + : _handle (INVALID_HANDLE_VALUE) +{ + ZeroMemory(&_write, offsetof(VDIPortBuffer, ring)); + _write.start = _write.end = _write.ring; + ZeroMemory(&_read, offsetof(VDIPortBuffer, ring)); + _read.start = _read.end = _read.ring; + _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); + } +} + +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() %s failed: %u", VIOSERIAL_PORT_PATH, GetLastError()); + return false; + } + _write.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (_write.overlap.hEvent == NULL) { + vd_printf("CreateEvent() failed: %u", GetLastError()); + return false; + } + _read.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (_read.overlap.hEvent == NULL) { + vd_printf("CreateEvent() failed: %u", GetLastError()); + return false; + } + return true; +} + +size_t VirtioVDIPort::write_ring_free_space() +{ + return (BUF_SIZE + _write.start - _write.end - 1) % BUF_SIZE; +} + +size_t VirtioVDIPort::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; +} + +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; +} + +void VirtioVDIPort::write_completion() +{ + DWORD bytes; + + if (!_write.pending) { + return; + } + if (!GetOverlappedResult(_handle, &_write.overlap, &bytes, FALSE)) { + vd_printf("GetOverlappedResult failed: %u", GetLastError()); + return; + } + _write.start = _write.ring + (_write.start - _write.ring + bytes) % BUF_SIZE; + _write.bytes = bytes; + _write.pending = false; +} + +size_t VirtioVDIPort::read_ring_size() +{ + return (BUF_SIZE + _read.end - _read.start) % BUF_SIZE; +} + +size_t VirtioVDIPort::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 VirtioVDIPort::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 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; +} + +void VirtioVDIPort::read_completion() +{ + DWORD bytes; + + if (!GetOverlappedResult(_handle, &_read.overlap, &bytes, FALSE) && + GetLastError() != ERROR_MORE_DATA) { + vd_printf("GetOverlappedResult failed: %u", GetLastError()); + return; + } + _read.end = _read.ring + (_read.end - _read.ring + bytes) % BUF_SIZE; + _read.bytes = bytes; + _read.pending = false; +} + +int VirtioVDIPort::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: %u", GetLastError()); + return VDI_PORT_ERROR; + } +} -- 1.7.3.4 _______________________________________________ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel