diff options
Diffstat (limited to 'qemu/qga/channel-win32.c')
-rw-r--r-- | qemu/qga/channel-win32.c | 357 |
1 files changed, 0 insertions, 357 deletions
diff --git a/qemu/qga/channel-win32.c b/qemu/qga/channel-win32.c deleted file mode 100644 index bb5966124..000000000 --- a/qemu/qga/channel-win32.c +++ /dev/null @@ -1,357 +0,0 @@ -#include "qemu/osdep.h" -#include <glib.h> -#include <windows.h> -#include <io.h> -#include "qga/guest-agent-core.h" -#include "qga/channel.h" - -typedef struct GAChannelReadState { - guint thread_id; - uint8_t *buf; - size_t buf_size; - size_t cur; /* current buffer start */ - size_t pending; /* pending buffered bytes to read */ - OVERLAPPED ov; - bool ov_pending; /* whether on async read is outstanding */ -} GAChannelReadState; - -struct GAChannel { - HANDLE handle; - GAChannelCallback cb; - gpointer user_data; - GAChannelReadState rstate; - GIOCondition pending_events; /* TODO: use GAWatch.pollfd.revents */ - GSource *source; -}; - -typedef struct GAWatch { - GSource source; - GPollFD pollfd; - GAChannel *channel; - GIOCondition events_mask; -} GAWatch; - -/* - * Called by glib prior to polling to set up poll events if polling is needed. - * - */ -static gboolean ga_channel_prepare(GSource *source, gint *timeout_ms) -{ - GAWatch *watch = (GAWatch *)source; - GAChannel *c = (GAChannel *)watch->channel; - GAChannelReadState *rs = &c->rstate; - DWORD count_read, count_to_read = 0; - bool success; - GIOCondition new_events = 0; - - g_debug("prepare"); - /* go ahead and submit another read if there's room in the buffer - * and no previous reads are outstanding - */ - if (!rs->ov_pending) { - if (rs->cur + rs->pending >= rs->buf_size) { - if (rs->cur) { - memmove(rs->buf, rs->buf + rs->cur, rs->pending); - rs->cur = 0; - } - } - count_to_read = rs->buf_size - rs->cur - rs->pending; - } - - if (rs->ov_pending || count_to_read <= 0) { - goto out; - } - - /* submit the read */ - success = ReadFile(c->handle, rs->buf + rs->cur + rs->pending, - count_to_read, &count_read, &rs->ov); - if (success) { - rs->pending += count_read; - rs->ov_pending = false; - } else { - if (GetLastError() == ERROR_IO_PENDING) { - rs->ov_pending = true; - } else { - new_events |= G_IO_ERR; - } - } - -out: - /* dont block forever, iterate the main loop every once and a while */ - *timeout_ms = 500; - /* if there's data in the read buffer, or another event is pending, - * skip polling and issue user cb. - */ - if (rs->pending) { - new_events |= G_IO_IN; - } - c->pending_events |= new_events; - return !!c->pending_events; -} - -/* - * Called by glib after an outstanding read request is completed. - */ -static gboolean ga_channel_check(GSource *source) -{ - GAWatch *watch = (GAWatch *)source; - GAChannel *c = (GAChannel *)watch->channel; - GAChannelReadState *rs = &c->rstate; - DWORD count_read, error; - BOOL success; - - GIOCondition new_events = 0; - - g_debug("check"); - - /* failing this implies we issued a read that completed immediately, - * yet no data was placed into the buffer (and thus we did not skip - * polling). but since EOF is not obtainable until we retrieve an - * overlapped result, it must be the case that there was data placed - * into the buffer, or an error was generated by Readfile(). in either - * case, we should've skipped the polling for this round. - */ - g_assert(rs->ov_pending); - - success = GetOverlappedResult(c->handle, &rs->ov, &count_read, FALSE); - if (success) { - g_debug("thread: overlapped result, count_read: %d", (int)count_read); - rs->pending += count_read; - new_events |= G_IO_IN; - } else { - error = GetLastError(); - if (error == 0 || error == ERROR_HANDLE_EOF || - error == ERROR_NO_SYSTEM_RESOURCES || - error == ERROR_OPERATION_ABORTED) { - /* note: On WinXP SP3 with rhel6ga virtio-win-1.1.16 vioser drivers, - * ENSR seems to be synonymous with when we'd normally expect - * ERROR_HANDLE_EOF. So treat it as such. Microsoft's - * recommendation for ERROR_NO_SYSTEM_RESOURCES is to - * retry the read, so this happens to work out anyway. On newer - * virtio-win driver, this seems to be replaced with EOA, so - * handle that in the same fashion. - */ - new_events |= G_IO_HUP; - } else if (error != ERROR_IO_INCOMPLETE) { - g_critical("error retrieving overlapped result: %d", (int)error); - new_events |= G_IO_ERR; - } - } - - if (new_events) { - rs->ov_pending = 0; - } - c->pending_events |= new_events; - - return !!c->pending_events; -} - -/* - * Called by glib after either prepare or check routines signal readiness - */ -static gboolean ga_channel_dispatch(GSource *source, GSourceFunc unused, - gpointer user_data) -{ - GAWatch *watch = (GAWatch *)source; - GAChannel *c = (GAChannel *)watch->channel; - GAChannelReadState *rs = &c->rstate; - gboolean success; - - g_debug("dispatch"); - success = c->cb(watch->pollfd.revents, c->user_data); - - if (c->pending_events & G_IO_ERR) { - g_critical("channel error, removing source"); - return false; - } - - /* TODO: replace rs->pending with watch->revents */ - c->pending_events &= ~G_IO_HUP; - if (!rs->pending) { - c->pending_events &= ~G_IO_IN; - } else { - c->pending_events = 0; - } - return success; -} - -static void ga_channel_finalize(GSource *source) -{ - g_debug("finalize"); -} - -GSourceFuncs ga_channel_watch_funcs = { - ga_channel_prepare, - ga_channel_check, - ga_channel_dispatch, - ga_channel_finalize -}; - -static GSource *ga_channel_create_watch(GAChannel *c) -{ - GSource *source = g_source_new(&ga_channel_watch_funcs, sizeof(GAWatch)); - GAWatch *watch = (GAWatch *)source; - - watch->channel = c; - watch->pollfd.fd = (gintptr) c->rstate.ov.hEvent; - g_source_add_poll(source, &watch->pollfd); - - return source; -} - -GIOStatus ga_channel_read(GAChannel *c, char *buf, size_t size, gsize *count) -{ - GAChannelReadState *rs = &c->rstate; - GIOStatus status; - size_t to_read = 0; - - if (c->pending_events & G_IO_ERR) { - return G_IO_STATUS_ERROR; - } - - *count = to_read = MIN(size, rs->pending); - if (to_read) { - memcpy(buf, rs->buf + rs->cur, to_read); - rs->cur += to_read; - rs->pending -= to_read; - status = G_IO_STATUS_NORMAL; - } else { - status = G_IO_STATUS_AGAIN; - } - - return status; -} - -static GIOStatus ga_channel_write(GAChannel *c, const char *buf, size_t size, - size_t *count) -{ - GIOStatus status; - OVERLAPPED ov = {0}; - BOOL ret; - DWORD written; - - ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - ret = WriteFile(c->handle, buf, size, &written, &ov); - if (!ret) { - if (GetLastError() == ERROR_IO_PENDING) { - /* write is pending */ - ret = GetOverlappedResult(c->handle, &ov, &written, TRUE); - if (!ret) { - if (!GetLastError()) { - status = G_IO_STATUS_AGAIN; - } else { - status = G_IO_STATUS_ERROR; - } - } else { - /* write is complete */ - status = G_IO_STATUS_NORMAL; - *count = written; - } - } else { - status = G_IO_STATUS_ERROR; - } - } else { - /* write returned immediately */ - status = G_IO_STATUS_NORMAL; - *count = written; - } - - if (ov.hEvent) { - CloseHandle(ov.hEvent); - ov.hEvent = NULL; - } - return status; -} - -GIOStatus ga_channel_write_all(GAChannel *c, const char *buf, size_t size) -{ - GIOStatus status = G_IO_STATUS_NORMAL; - size_t count = 0; - - while (size) { - status = ga_channel_write(c, buf, size, &count); - if (status == G_IO_STATUS_NORMAL) { - size -= count; - buf += count; - } else if (status != G_IO_STATUS_AGAIN) { - break; - } - } - - return status; -} - -static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method, - const gchar *path) -{ - COMMTIMEOUTS comTimeOut = {0}; - gchar newpath[MAXPATHLEN] = {0}; - comTimeOut.ReadIntervalTimeout = 1; - - if (method != GA_CHANNEL_VIRTIO_SERIAL && method != GA_CHANNEL_ISA_SERIAL) { - g_critical("unsupported communication method"); - return false; - } - - if (method == GA_CHANNEL_ISA_SERIAL){ - snprintf(newpath, sizeof(newpath), "\\\\.\\%s", path); - }else { - g_strlcpy(newpath, path, sizeof(newpath)); - } - - c->handle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, - FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); - if (c->handle == INVALID_HANDLE_VALUE) { - g_critical("error opening path %s", newpath); - return false; - } - - if (method == GA_CHANNEL_ISA_SERIAL && !SetCommTimeouts(c->handle,&comTimeOut)) { - g_critical("error setting timeout for com port: %lu",GetLastError()); - CloseHandle(c->handle); - return false; - } - - return true; -} - -GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path, - GAChannelCallback cb, gpointer opaque) -{ - GAChannel *c = g_new0(GAChannel, 1); - SECURITY_ATTRIBUTES sec_attrs; - - if (!ga_channel_open(c, method, path)) { - g_critical("error opening channel"); - g_free(c); - return NULL; - } - - c->cb = cb; - c->user_data = opaque; - - sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES); - sec_attrs.lpSecurityDescriptor = NULL; - sec_attrs.bInheritHandle = false; - - c->rstate.buf_size = QGA_READ_COUNT_DEFAULT; - c->rstate.buf = g_malloc(QGA_READ_COUNT_DEFAULT); - c->rstate.ov.hEvent = CreateEvent(&sec_attrs, FALSE, FALSE, NULL); - - c->source = ga_channel_create_watch(c); - g_source_attach(c->source, NULL); - return c; -} - -void ga_channel_free(GAChannel *c) -{ - if (c->source) { - g_source_destroy(c->source); - } - if (c->rstate.ov.hEvent) { - CloseHandle(c->rstate.ov.hEvent); - } - g_free(c->rstate.buf); - g_free(c); -} |