xref: /openbmc/qemu/qga/channel-win32.c (revision b45c03f5)
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     COMMTIMEOUTS comTimeOut = {0};
291     gchar newpath[MAXPATHLEN] = {0};
292     comTimeOut.ReadIntervalTimeout = 1;
293 
294     if (method != GA_CHANNEL_VIRTIO_SERIAL && method != GA_CHANNEL_ISA_SERIAL) {
295         g_critical("unsupported communication method");
296         return false;
297     }
298 
299     if (method == GA_CHANNEL_ISA_SERIAL){
300         snprintf(newpath, sizeof(newpath), "\\\\.\\%s", path);
301     }else {
302         g_strlcpy(newpath, path, sizeof(newpath));
303     }
304 
305     c->handle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
306                            OPEN_EXISTING,
307                            FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);
308     if (c->handle == INVALID_HANDLE_VALUE) {
309         g_critical("error opening path %s", newpath);
310         return false;
311     }
312 
313     if (method == GA_CHANNEL_ISA_SERIAL && !SetCommTimeouts(c->handle,&comTimeOut)) {
314         g_critical("error setting timeout for com port: %lu",GetLastError());
315         CloseHandle(c->handle);
316         return false;
317     }
318 
319     return true;
320 }
321 
322 GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
323                           GAChannelCallback cb, gpointer opaque)
324 {
325     GAChannel *c = g_malloc0(sizeof(GAChannel));
326     SECURITY_ATTRIBUTES sec_attrs;
327 
328     if (!ga_channel_open(c, method, path)) {
329         g_critical("error opening channel");
330         g_free(c);
331         return NULL;
332     }
333 
334     c->cb = cb;
335     c->user_data = opaque;
336 
337     sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
338     sec_attrs.lpSecurityDescriptor = NULL;
339     sec_attrs.bInheritHandle = false;
340 
341     c->rstate.buf_size = QGA_READ_COUNT_DEFAULT;
342     c->rstate.buf = g_malloc(QGA_READ_COUNT_DEFAULT);
343     c->rstate.ov.hEvent = CreateEvent(&sec_attrs, FALSE, FALSE, NULL);
344 
345     c->source = ga_channel_create_watch(c);
346     g_source_attach(c->source, NULL);
347     return c;
348 }
349 
350 void ga_channel_free(GAChannel *c)
351 {
352     if (c->source) {
353         g_source_destroy(c->source);
354     }
355     if (c->rstate.ov.hEvent) {
356         CloseHandle(c->rstate.ov.hEvent);
357     }
358     g_free(c->rstate.buf);
359     g_free(c);
360 }
361