|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.