blob: 779007e39b33816934221ca4a69888b9b47a6e9d [file] [log] [blame]
Peter Maydell4459bf32016-01-29 17:49:58 +00001#include "qemu/osdep.h"
Michael Roth7868e262012-01-20 19:01:30 -06002#include <windows.h>
Michael Roth7868e262012-01-20 19:01:30 -06003#include <io.h>
Michael S. Tsirkindc032722018-05-03 22:50:57 +03004#include "guest-agent-core.h"
5#include "channel.h"
Michael Roth7868e262012-01-20 19:01:30 -06006
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:
Stefan Weilcb8d4c82016-03-23 15:59:57 +010079 /* don't block forever, iterate the main loop every once in a while */
Michael Roth7868e262012-01-20 19:01:30 -060080 *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
Jeff Codyb71706d2012-03-15 14:26:18 -0400258 if (ov.hEvent) {
259 CloseHandle(ov.hEvent);
260 ov.hEvent = NULL;
261 }
Michael Roth7868e262012-01-20 19:01:30 -0600262 return status;
263}
264
265GIOStatus ga_channel_write_all(GAChannel *c, const char *buf, size_t size)
266{
Dong Xu Wangc7e775e2013-05-09 15:53:50 +0800267 GIOStatus status = G_IO_STATUS_NORMAL;
Michael Rothe853ea12015-10-17 10:31:16 -0500268 size_t count = 0;
Michael Roth7868e262012-01-20 19:01:30 -0600269
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{
Miki Mishaela749f422014-01-15 04:33:44 -0500286 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) {
Michael Roth7868e262012-01-20 19:01:30 -0600291 g_critical("unsupported communication method");
292 return false;
293 }
294
AlexChen0697e9e2020-10-26 17:05:38 +0800295 if (method == GA_CHANNEL_ISA_SERIAL) {
Miki Mishaela749f422014-01-15 04:33:44 -0500296 snprintf(newpath, sizeof(newpath), "\\\\.\\%s", path);
AlexChen0697e9e2020-10-26 17:05:38 +0800297 } else {
Miki Mishaela749f422014-01-15 04:33:44 -0500298 g_strlcpy(newpath, path, sizeof(newpath));
299 }
300
301 c->handle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
Michael Roth7868e262012-01-20 19:01:30 -0600302 OPEN_EXISTING,
303 FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);
304 if (c->handle == INVALID_HANDLE_VALUE) {
Philippe Mathieu-Daudéd1eddab2020-02-28 11:07:26 +0100305 g_autofree gchar *emsg = g_win32_error_message(GetLastError());
306 g_critical("error opening path %s: %s", newpath, emsg);
Michael Roth7868e262012-01-20 19:01:30 -0600307 return false;
308 }
309
AlexChen0697e9e2020-10-26 17:05:38 +0800310 if (method == GA_CHANNEL_ISA_SERIAL
311 && !SetCommTimeouts(c->handle, &comTimeOut)) {
Philippe Mathieu-Daudé672db772020-02-28 11:07:25 +0100312 g_autofree gchar *emsg = g_win32_error_message(GetLastError());
313 g_critical("error setting timeout for com port: %s", emsg);
Miki Mishaela749f422014-01-15 04:33:44 -0500314 CloseHandle(c->handle);
315 return false;
316 }
317
Michael Roth7868e262012-01-20 19:01:30 -0600318 return true;
319}
320
321GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
Stefan Hajnoczi26de2292017-01-06 15:29:30 +0000322 int listen_fd, GAChannelCallback cb, gpointer opaque)
Michael Roth7868e262012-01-20 19:01:30 -0600323{
Markus Armbrusterf3a06402015-09-14 13:50:44 +0200324 GAChannel *c = g_new0(GAChannel, 1);
Michael Roth7868e262012-01-20 19:01:30 -0600325 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
349void 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}