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