xref: /openbmc/qemu/qga/channel-win32.c (revision 7ef295ea)
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 
8 typedef 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 
18 struct 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 
27 typedef 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  */
38 static 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 
79 out:
80     /* dont block forever, iterate the main loop every once and 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  */
95 static 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  */
152 static 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 
178 static void ga_channel_finalize(GSource *source)
179 {
180     g_debug("finalize");
181 }
182 
183 GSourceFuncs ga_channel_watch_funcs = {
184     ga_channel_prepare,
185     ga_channel_check,
186     ga_channel_dispatch,
187     ga_channel_finalize
188 };
189 
190 static 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 
202 GIOStatus 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 
225 static 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 
266 GIOStatus 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 
284 static 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 
319 GAChannel *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 
347 void 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