qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

channel-win32.c (10334B)


      1 #include "qemu/osdep.h"
      2 #include <windows.h>
      3 #include <io.h>
      4 #include "guest-agent-core.h"
      5 #include "channel.h"
      6 
      7 typedef 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 
     17 struct 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 
     26 typedef 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  */
     37 static 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 
     78 out:
     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  */
     94 static 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  */
    151 static 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 
    177 static void ga_channel_finalize(GSource *source)
    178 {
    179     g_debug("finalize");
    180 }
    181 
    182 GSourceFuncs ga_channel_watch_funcs = {
    183     ga_channel_prepare,
    184     ga_channel_check,
    185     ga_channel_dispatch,
    186     ga_channel_finalize
    187 };
    188 
    189 static 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 
    201 GIOStatus 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 
    224 static 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 
    265 GIOStatus 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 
    283 static 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_autofree gchar *emsg = g_win32_error_message(GetLastError());
    306         g_critical("error opening path %s: %s", newpath, emsg);
    307         return false;
    308     }
    309 
    310     if (method == GA_CHANNEL_ISA_SERIAL
    311             && !SetCommTimeouts(c->handle, &comTimeOut)) {
    312         g_autofree gchar *emsg = g_win32_error_message(GetLastError());
    313         g_critical("error setting timeout for com port: %s", emsg);
    314         CloseHandle(c->handle);
    315         return false;
    316     }
    317 
    318     return true;
    319 }
    320 
    321 GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
    322                           int listen_fd, GAChannelCallback cb, gpointer opaque)
    323 {
    324     GAChannel *c = g_new0(GAChannel, 1);
    325     SECURITY_ATTRIBUTES sec_attrs;
    326 
    327     if (!ga_channel_open(c, method, path)) {
    328         g_critical("error opening channel");
    329         g_free(c);
    330         return NULL;
    331     }
    332 
    333     c->cb = cb;
    334     c->user_data = opaque;
    335 
    336     sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
    337     sec_attrs.lpSecurityDescriptor = NULL;
    338     sec_attrs.bInheritHandle = false;
    339 
    340     c->rstate.buf_size = QGA_READ_COUNT_DEFAULT;
    341     c->rstate.buf = g_malloc(QGA_READ_COUNT_DEFAULT);
    342     c->rstate.ov.hEvent = CreateEvent(&sec_attrs, FALSE, FALSE, NULL);
    343 
    344     c->source = ga_channel_create_watch(c);
    345     g_source_attach(c->source, NULL);
    346     return c;
    347 }
    348 
    349 void ga_channel_free(GAChannel *c)
    350 {
    351     if (c->source) {
    352         g_source_destroy(c->source);
    353     }
    354     if (c->rstate.ov.hEvent) {
    355         CloseHandle(c->rstate.ov.hEvent);
    356     }
    357     g_free(c->rstate.buf);
    358     g_free(c);
    359 }