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
8typedef struct GAChannelReadState {
9 guint thread_id;
10 uint8_t *buf;
11 size_t buf_size;
12 size_t cur;
13 size_t pending;
14 OVERLAPPED ov;
15 bool ov_pending;
16} GAChannelReadState;
17
18struct GAChannel {
19 HANDLE handle;
20 GAChannelCallback cb;
21 gpointer user_data;
22 GAChannelReadState rstate;
23 GIOCondition pending_events;
24 GSource *source;
25};
26
27typedef struct GAWatch {
28 GSource source;
29 GPollFD pollfd;
30 GAChannel *channel;
31 GIOCondition events_mask;
32} GAWatch;
33
34
35
36
37
38static 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
49
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
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
79out:
80
81 *timeout_ms = 500;
82
83
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
94
95static 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
108
109
110
111
112
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
127
128
129
130
131
132
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
151
152static 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
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
178static void ga_channel_finalize(GSource *source)
179{
180 g_debug("finalize");
181}
182
183GSourceFuncs ga_channel_watch_funcs = {
184 ga_channel_prepare,
185 ga_channel_check,
186 ga_channel_dispatch,
187 ga_channel_finalize
188};
189
190static 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
202GIOStatus 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
225static 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
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
247 status = G_IO_STATUS_NORMAL;
248 *count = written;
249 }
250 } else {
251 status = G_IO_STATUS_ERROR;
252 }
253 } else {
254
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
266GIOStatus 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
284static 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
319GAChannel *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
347void 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