8
#include "qga/guest-agent-core.h"
9
#include "qga/channel.h"
11
typedef struct GAChannelReadState {
15
size_t cur; /* current buffer start */
16
size_t pending; /* pending buffered bytes to read */
18
bool ov_pending; /* whether on async read is outstanding */
25
GAChannelReadState rstate;
26
GIOCondition pending_events; /* TODO: use GAWatch.pollfd.revents */
30
typedef struct GAWatch {
34
GIOCondition events_mask;
38
* Called by glib prior to polling to set up poll events if polling is needed.
41
static gboolean ga_channel_prepare(GSource *source, gint *timeout_ms)
43
GAWatch *watch = (GAWatch *)source;
44
GAChannel *c = (GAChannel *)watch->channel;
45
GAChannelReadState *rs = &c->rstate;
46
DWORD count_read, count_to_read = 0;
48
GIOCondition new_events = 0;
51
/* go ahead and submit another read if there's room in the buffer
52
* and no previous reads are outstanding
54
if (!rs->ov_pending) {
55
if (rs->cur + rs->pending >= rs->buf_size) {
57
memmove(rs->buf, rs->buf + rs->cur, rs->pending);
61
count_to_read = rs->buf_size - rs->cur - rs->pending;
64
if (rs->ov_pending || count_to_read <= 0) {
69
success = ReadFile(c->handle, rs->buf + rs->cur + rs->pending,
70
count_to_read, &count_read, &rs->ov);
72
rs->pending += count_read;
73
rs->ov_pending = false;
75
if (GetLastError() == ERROR_IO_PENDING) {
76
rs->ov_pending = true;
78
new_events |= G_IO_ERR;
83
/* dont block forever, iterate the main loop every once and a while */
85
/* if there's data in the read buffer, or another event is pending,
86
* skip polling and issue user cb.
89
new_events |= G_IO_IN;
91
c->pending_events |= new_events;
92
return !!c->pending_events;
96
* Called by glib after an outstanding read request is completed.
98
static gboolean ga_channel_check(GSource *source)
100
GAWatch *watch = (GAWatch *)source;
101
GAChannel *c = (GAChannel *)watch->channel;
102
GAChannelReadState *rs = &c->rstate;
103
DWORD count_read, error;
106
GIOCondition new_events = 0;
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.
117
g_assert(rs->ov_pending);
119
success = GetOverlappedResult(c->handle, &rs->ov, &count_read, FALSE);
121
g_debug("thread: overlapped result, count_read: %d", (int)count_read);
122
rs->pending += count_read;
123
new_events |= G_IO_IN;
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.
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;
147
c->pending_events |= new_events;
149
return !!c->pending_events;
153
* Called by glib after either prepare or check routines signal readiness
155
static gboolean ga_channel_dispatch(GSource *source, GSourceFunc unused,
158
GAWatch *watch = (GAWatch *)source;
159
GAChannel *c = (GAChannel *)watch->channel;
160
GAChannelReadState *rs = &c->rstate;
164
success = c->cb(watch->pollfd.revents, c->user_data);
166
if (c->pending_events & G_IO_ERR) {
167
g_critical("channel error, removing source");
171
/* TODO: replace rs->pending with watch->revents */
172
c->pending_events &= ~G_IO_HUP;
174
c->pending_events &= ~G_IO_IN;
176
c->pending_events = 0;
181
static void ga_channel_finalize(GSource *source)
186
GSourceFuncs ga_channel_watch_funcs = {
193
static GSource *ga_channel_create_watch(GAChannel *c)
195
GSource *source = g_source_new(&ga_channel_watch_funcs, sizeof(GAWatch));
196
GAWatch *watch = (GAWatch *)source;
199
watch->pollfd.fd = (gintptr) c->rstate.ov.hEvent;
200
g_source_add_poll(source, &watch->pollfd);
205
GIOStatus ga_channel_read(GAChannel *c, char *buf, size_t size, gsize *count)
207
GAChannelReadState *rs = &c->rstate;
211
if (c->pending_events & G_IO_ERR) {
212
return G_IO_STATUS_ERROR;
215
*count = to_read = MIN(size, rs->pending);
217
memcpy(buf, rs->buf + rs->cur, to_read);
219
rs->pending -= to_read;
220
status = G_IO_STATUS_NORMAL;
222
status = G_IO_STATUS_AGAIN;
228
static GIOStatus ga_channel_write(GAChannel *c, const char *buf, size_t size,
236
ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
237
ret = WriteFile(c->handle, buf, size, &written, &ov);
239
if (GetLastError() == ERROR_IO_PENDING) {
240
/* write is pending */
241
ret = GetOverlappedResult(c->handle, &ov, &written, TRUE);
243
if (!GetLastError()) {
244
status = G_IO_STATUS_AGAIN;
246
status = G_IO_STATUS_ERROR;
249
/* write is complete */
250
status = G_IO_STATUS_NORMAL;
254
status = G_IO_STATUS_ERROR;
257
/* write returned immediately */
258
status = G_IO_STATUS_NORMAL;
265
GIOStatus ga_channel_write_all(GAChannel *c, const char *buf, size_t size)
267
GIOStatus status = G_IO_STATUS_NORMAL;;
271
status = ga_channel_write(c, buf, size, &count);
272
if (status == G_IO_STATUS_NORMAL) {
275
} else if (status != G_IO_STATUS_AGAIN) {
283
static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method,
286
if (!method == GA_CHANNEL_VIRTIO_SERIAL) {
287
g_critical("unsupported communication method");
291
c->handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
293
FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);
294
if (c->handle == INVALID_HANDLE_VALUE) {
295
g_critical("error opening path");
302
GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
303
GAChannelCallback cb, gpointer opaque)
305
GAChannel *c = g_malloc0(sizeof(GAChannel));
306
SECURITY_ATTRIBUTES sec_attrs;
308
if (!ga_channel_open(c, method, path)) {
309
g_critical("error opening channel");
315
c->user_data = opaque;
317
sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
318
sec_attrs.lpSecurityDescriptor = NULL;
319
sec_attrs.bInheritHandle = false;
321
c->rstate.buf_size = QGA_READ_COUNT_DEFAULT;
322
c->rstate.buf = g_malloc(QGA_READ_COUNT_DEFAULT);
323
c->rstate.ov.hEvent = CreateEvent(&sec_attrs, FALSE, FALSE, NULL);
325
c->source = ga_channel_create_watch(c);
326
g_source_attach(c->source, NULL);
330
void ga_channel_free(GAChannel *c)
333
g_source_destroy(c->source);
335
if (c->rstate.ov.hEvent) {
336
CloseHandle(c->rstate.ov.hEvent);
338
g_free(c->rstate.buf);