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