qemu/qga/channel-win32.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2#include <glib.h>
   3#include <windows.h>
   4#include <io.h>
   5#include "qga/guest-agent-core.h"
   6#include "qga/channel.h"
   7
   8typedef struct GAChannelReadState {
   9    guint thread_id;
  10    uint8_t *buf;
  11    size_t buf_size;
  12    size_t cur; /* current buffer start */
  13    size_t pending; /* pending buffered bytes to read */
  14    OVERLAPPED ov;
  15    bool ov_pending; /* whether on async read is outstanding */
  16} GAChannelReadState;
  17
  18struct GAChannel {
  19    HANDLE handle;
  20    GAChannelCallback cb;
  21    gpointer user_data;
  22    GAChannelReadState rstate;
  23    GIOCondition pending_events; /* TODO: use GAWatch.pollfd.revents */
  24    GSource *source;
  25};
  26
  27typedef struct GAWatch {
  28    GSource source;
  29    GPollFD pollfd;
  30    GAChannel *channel;
  31    GIOCondition events_mask;
  32} GAWatch;
  33
  34/*
  35 * Called by glib prior to polling to set up poll events if polling is needed.
  36 *
  37 */
  38static gboolean ga_channel_prepare(GSource *source, gint *timeout_ms)
  39{
  40    GAWatch *watch = (GAWatch *)source;
  41    GAChannel *c = (GAChannel *)watch->channel;
  42    GAChannelReadState *rs = &c->rstate;
  43    DWORD count_read, count_to_read = 0;
  44    bool success;
  45    GIOCondition new_events = 0;
  46
  47    g_debug("prepare");
  48    /* go ahead and submit another read if there's room in the buffer
  49     * and no previous reads are outstanding
  50     */
  51    if (!rs->ov_pending) {
  52        if (rs->cur + rs->pending >= rs->buf_size) {
  53            if (rs->cur) {
  54                memmove(rs->buf, rs->buf + rs->cur, rs->pending);
  55                rs->cur = 0;
  56            }
  57        }
  58        count_to_read = rs->buf_size - rs->cur - rs->pending;
  59    }
  60
  61    if (rs->ov_pending || count_to_read <= 0) {
  62            goto out;
  63    }
  64
  65    /* submit the read */
  66    success = ReadFile(c->handle, rs->buf + rs->cur + rs->pending,
  67                       count_to_read, &count_read, &rs->ov);
  68    if (success) {
  69        rs->pending += count_read;
  70        rs->ov_pending = false;
  71    } else {
  72        if (GetLastError() == ERROR_IO_PENDING) {
  73            rs->ov_pending = true;
  74        } else {
  75            new_events |= G_IO_ERR;
  76        }
  77    }
  78
  79out:
  80    /* don't block forever, iterate the main loop every once in a while */
  81    *timeout_ms = 500;
  82    /* if there's data in the read buffer, or another event is pending,
  83     * skip polling and issue user cb.
  84     */
  85    if (rs->pending) {
  86        new_events |= G_IO_IN;
  87    }
  88    c->pending_events |= new_events;
  89    return !!c->pending_events;
  90}
  91
  92/*
  93 * Called by glib after an outstanding read request is completed.
  94 */
  95static gboolean ga_channel_check(GSource *source)
  96{
  97    GAWatch *watch = (GAWatch *)source;
  98    GAChannel *c = (GAChannel *)watch->channel;
  99    GAChannelReadState *rs = &c->rstate;
 100    DWORD count_read, error;
 101    BOOL success;
 102
 103    GIOCondition new_events = 0;
 104
 105    g_debug("check");
 106
 107    /* failing this implies we issued a read that completed immediately,
 108     * yet no data was placed into the buffer (and thus we did not skip
 109     * polling). but since EOF is not obtainable until we retrieve an
 110     * overlapped result, it must be the case that there was data placed
 111     * into the buffer, or an error was generated by Readfile(). in either
 112     * case, we should've skipped the polling for this round.
 113     */
 114    g_assert(rs->ov_pending);
 115
 116    success = GetOverlappedResult(c->handle, &rs->ov, &count_read, FALSE);
 117    if (success) {
 118        g_debug("thread: overlapped result, count_read: %d", (int)count_read);
 119        rs->pending += count_read;
 120        new_events |= G_IO_IN;
 121    } else {
 122        error = GetLastError();
 123        if (error == 0 || error == ERROR_HANDLE_EOF ||
 124            error == ERROR_NO_SYSTEM_RESOURCES ||
 125            error == ERROR_OPERATION_ABORTED) {
 126            /* note: On WinXP SP3 with rhel6ga virtio-win-1.1.16 vioser drivers,
 127             * ENSR seems to be synonymous with when we'd normally expect
 128             * ERROR_HANDLE_EOF. So treat it as such. Microsoft's
 129             * recommendation for ERROR_NO_SYSTEM_RESOURCES is to
 130             * retry the read, so this happens to work out anyway. On newer
 131             * virtio-win driver, this seems to be replaced with EOA, so
 132             * handle that in the same fashion.
 133             */
 134            new_events |= G_IO_HUP;
 135        } else if (error != ERROR_IO_INCOMPLETE) {
 136            g_critical("error retrieving overlapped result: %d", (int)error);
 137            new_events |= G_IO_ERR;
 138        }
 139    }
 140
 141    if (new_events) {
 142        rs->ov_pending = 0;
 143    }
 144    c->pending_events |= new_events;
 145
 146    return !!c->pending_events;
 147}
 148
 149/*
 150 * Called by glib after either prepare or check routines signal readiness
 151 */
 152static gboolean ga_channel_dispatch(GSource *source, GSourceFunc unused,
 153                                    gpointer user_data)
 154{
 155    GAWatch *watch = (GAWatch *)source;
 156    GAChannel *c = (GAChannel *)watch->channel;
 157    GAChannelReadState *rs = &c->rstate;
 158    gboolean success;
 159
 160    g_debug("dispatch");
 161    success = c->cb(watch->pollfd.revents, c->user_data);
 162
 163    if (c->pending_events & G_IO_ERR) {
 164        g_critical("channel error, removing source");
 165        return false;
 166    }
 167
 168    /* TODO: replace rs->pending with watch->revents */
 169    c->pending_events &= ~G_IO_HUP;
 170    if (!rs->pending) {
 171        c->pending_events &= ~G_IO_IN;
 172    } else {
 173        c->pending_events = 0;
 174    }
 175    return success;
 176}
 177
 178static void ga_channel_finalize(GSource *source)
 179{
 180    g_debug("finalize");
 181}
 182
 183GSourceFuncs ga_channel_watch_funcs = {
 184    ga_channel_prepare,
 185    ga_channel_check,
 186    ga_channel_dispatch,
 187    ga_channel_finalize
 188};
 189
 190static GSource *ga_channel_create_watch(GAChannel *c)
 191{
 192    GSource *source = g_source_new(&ga_channel_watch_funcs, sizeof(GAWatch));
 193    GAWatch *watch = (GAWatch *)source;
 194
 195    watch->channel = c;
 196    watch->pollfd.fd = (gintptr) c->rstate.ov.hEvent;
 197    g_source_add_poll(source, &watch->pollfd);
 198
 199    return source;
 200}
 201
 202GIOStatus ga_channel_read(GAChannel *c, char *buf, size_t size, gsize *count)
 203{
 204    GAChannelReadState *rs = &c->rstate;
 205    GIOStatus status;
 206    size_t to_read = 0;
 207
 208    if (c->pending_events & G_IO_ERR) {
 209        return G_IO_STATUS_ERROR;
 210    }
 211
 212    *count = to_read = MIN(size, rs->pending);
 213    if (to_read) {
 214        memcpy(buf, rs->buf + rs->cur, to_read);
 215        rs->cur += to_read;
 216        rs->pending -= to_read;
 217        status = G_IO_STATUS_NORMAL;
 218    } else {
 219        status = G_IO_STATUS_AGAIN;
 220    }
 221
 222    return status;
 223}
 224
 225static GIOStatus ga_channel_write(GAChannel *c, const char *buf, size_t size,
 226                                  size_t *count)
 227{
 228    GIOStatus status;
 229    OVERLAPPED ov = {0};
 230    BOOL ret;
 231    DWORD written;
 232
 233    ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 234    ret = WriteFile(c->handle, buf, size, &written, &ov);
 235    if (!ret) {
 236        if (GetLastError() == ERROR_IO_PENDING) {
 237            /* write is pending */
 238            ret = GetOverlappedResult(c->handle, &ov, &written, TRUE);
 239            if (!ret) {
 240                if (!GetLastError()) {
 241                    status = G_IO_STATUS_AGAIN;
 242                } else {
 243                    status = G_IO_STATUS_ERROR;
 244                }
 245            } else {
 246                /* write is complete */
 247                status = G_IO_STATUS_NORMAL;
 248                *count = written;
 249            }
 250        } else {
 251            status = G_IO_STATUS_ERROR;
 252        }
 253    } else {
 254        /* write returned immediately */
 255        status = G_IO_STATUS_NORMAL;
 256        *count = written;
 257    }
 258
 259    if (ov.hEvent) {
 260        CloseHandle(ov.hEvent);
 261        ov.hEvent = NULL;
 262    }
 263    return status;
 264}
 265
 266GIOStatus ga_channel_write_all(GAChannel *c, const char *buf, size_t size)
 267{
 268    GIOStatus status = G_IO_STATUS_NORMAL;
 269    size_t count = 0;
 270
 271    while (size) {
 272        status = ga_channel_write(c, buf, size, &count);
 273        if (status == G_IO_STATUS_NORMAL) {
 274            size -= count;
 275            buf += count;
 276        } else if (status != G_IO_STATUS_AGAIN) {
 277            break;
 278        }
 279    }
 280
 281    return status;
 282}
 283
 284static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method,
 285                                const gchar *path)
 286{
 287    COMMTIMEOUTS comTimeOut = {0};
 288    gchar newpath[MAXPATHLEN] = {0};
 289    comTimeOut.ReadIntervalTimeout = 1;
 290
 291    if (method != GA_CHANNEL_VIRTIO_SERIAL && method != GA_CHANNEL_ISA_SERIAL) {
 292        g_critical("unsupported communication method");
 293        return false;
 294    }
 295
 296    if (method == GA_CHANNEL_ISA_SERIAL){
 297        snprintf(newpath, sizeof(newpath), "\\\\.\\%s", path);
 298    }else {
 299        g_strlcpy(newpath, path, sizeof(newpath));
 300    }
 301
 302    c->handle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
 303                           OPEN_EXISTING,
 304                           FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);
 305    if (c->handle == INVALID_HANDLE_VALUE) {
 306        g_critical("error opening path %s", newpath);
 307        return false;
 308    }
 309
 310    if (method == GA_CHANNEL_ISA_SERIAL && !SetCommTimeouts(c->handle,&comTimeOut)) {
 311        g_critical("error setting timeout for com port: %lu",GetLastError());
 312        CloseHandle(c->handle);
 313        return false;
 314    }
 315
 316    return true;
 317}
 318
 319GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
 320                          GAChannelCallback cb, gpointer opaque)
 321{
 322    GAChannel *c = g_new0(GAChannel, 1);
 323    SECURITY_ATTRIBUTES sec_attrs;
 324
 325    if (!ga_channel_open(c, method, path)) {
 326        g_critical("error opening channel");
 327        g_free(c);
 328        return NULL;
 329    }
 330
 331    c->cb = cb;
 332    c->user_data = opaque;
 333
 334    sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
 335    sec_attrs.lpSecurityDescriptor = NULL;
 336    sec_attrs.bInheritHandle = false;
 337
 338    c->rstate.buf_size = QGA_READ_COUNT_DEFAULT;
 339    c->rstate.buf = g_malloc(QGA_READ_COUNT_DEFAULT);
 340    c->rstate.ov.hEvent = CreateEvent(&sec_attrs, FALSE, FALSE, NULL);
 341
 342    c->source = ga_channel_create_watch(c);
 343    g_source_attach(c->source, NULL);
 344    return c;
 345}
 346
 347void ga_channel_free(GAChannel *c)
 348{
 349    if (c->source) {
 350        g_source_destroy(c->source);
 351    }
 352    if (c->rstate.ov.hEvent) {
 353        CloseHandle(c->rstate.ov.hEvent);
 354    }
 355    g_free(c->rstate.buf);
 356    g_free(c);
 357}
 358