Statistics
| Branch: | Revision:

root / qga / channel-win32.c @ 1ab516ed

History | View | Annotate | Download (9.5 kB)

1 7868e26e Michael Roth
#include <stdlib.h>
2 7868e26e Michael Roth
#include <stdio.h>
3 7868e26e Michael Roth
#include <stdbool.h>
4 7868e26e Michael Roth
#include <glib.h>
5 7868e26e Michael Roth
#include <windows.h>
6 7868e26e Michael Roth
#include <errno.h>
7 7868e26e Michael Roth
#include <io.h>
8 7868e26e Michael Roth
#include "qga/guest-agent-core.h"
9 7868e26e Michael Roth
#include "qga/channel.h"
10 7868e26e Michael Roth
11 7868e26e Michael Roth
typedef struct GAChannelReadState {
12 7868e26e Michael Roth
    guint thread_id;
13 7868e26e Michael Roth
    uint8_t *buf;
14 7868e26e Michael Roth
    size_t buf_size;
15 7868e26e Michael Roth
    size_t cur; /* current buffer start */
16 7868e26e Michael Roth
    size_t pending; /* pending buffered bytes to read */
17 7868e26e Michael Roth
    OVERLAPPED ov;
18 7868e26e Michael Roth
    bool ov_pending; /* whether on async read is outstanding */
19 7868e26e Michael Roth
} GAChannelReadState;
20 7868e26e Michael Roth
21 7868e26e Michael Roth
struct GAChannel {
22 7868e26e Michael Roth
    HANDLE handle;
23 7868e26e Michael Roth
    GAChannelCallback cb;
24 7868e26e Michael Roth
    gpointer user_data;
25 7868e26e Michael Roth
    GAChannelReadState rstate;
26 7868e26e Michael Roth
    GIOCondition pending_events; /* TODO: use GAWatch.pollfd.revents */
27 7868e26e Michael Roth
    GSource *source;
28 7868e26e Michael Roth
};
29 7868e26e Michael Roth
30 7868e26e Michael Roth
typedef struct GAWatch {
31 7868e26e Michael Roth
    GSource source;
32 7868e26e Michael Roth
    GPollFD pollfd;
33 7868e26e Michael Roth
    GAChannel *channel;
34 7868e26e Michael Roth
    GIOCondition events_mask;
35 7868e26e Michael Roth
} GAWatch;
36 7868e26e Michael Roth
37 7868e26e Michael Roth
/*
38 7868e26e Michael Roth
 * Called by glib prior to polling to set up poll events if polling is needed.
39 7868e26e Michael Roth
 *
40 7868e26e Michael Roth
 */
41 7868e26e Michael Roth
static gboolean ga_channel_prepare(GSource *source, gint *timeout_ms)
42 7868e26e Michael Roth
{
43 7868e26e Michael Roth
    GAWatch *watch = (GAWatch *)source;
44 7868e26e Michael Roth
    GAChannel *c = (GAChannel *)watch->channel;
45 7868e26e Michael Roth
    GAChannelReadState *rs = &c->rstate;
46 7868e26e Michael Roth
    DWORD count_read, count_to_read = 0;
47 7868e26e Michael Roth
    bool success;
48 7868e26e Michael Roth
    GIOCondition new_events = 0;
49 7868e26e Michael Roth
50 7868e26e Michael Roth
    g_debug("prepare");
51 7868e26e Michael Roth
    /* go ahead and submit another read if there's room in the buffer
52 7868e26e Michael Roth
     * and no previous reads are outstanding
53 7868e26e Michael Roth
     */
54 7868e26e Michael Roth
    if (!rs->ov_pending) {
55 7868e26e Michael Roth
        if (rs->cur + rs->pending >= rs->buf_size) {
56 7868e26e Michael Roth
            if (rs->cur) {
57 7868e26e Michael Roth
                memmove(rs->buf, rs->buf + rs->cur, rs->pending);
58 7868e26e Michael Roth
                rs->cur = 0;
59 7868e26e Michael Roth
            }
60 7868e26e Michael Roth
        }
61 7868e26e Michael Roth
        count_to_read = rs->buf_size - rs->cur - rs->pending;
62 7868e26e Michael Roth
    }
63 7868e26e Michael Roth
64 7868e26e Michael Roth
    if (rs->ov_pending || count_to_read <= 0) {
65 7868e26e Michael Roth
            goto out;
66 7868e26e Michael Roth
    }
67 7868e26e Michael Roth
68 7868e26e Michael Roth
    /* submit the read */
69 7868e26e Michael Roth
    success = ReadFile(c->handle, rs->buf + rs->cur + rs->pending,
70 7868e26e Michael Roth
                       count_to_read, &count_read, &rs->ov);
71 7868e26e Michael Roth
    if (success) {
72 7868e26e Michael Roth
        rs->pending += count_read;
73 7868e26e Michael Roth
        rs->ov_pending = false;
74 7868e26e Michael Roth
    } else {
75 7868e26e Michael Roth
        if (GetLastError() == ERROR_IO_PENDING) {
76 7868e26e Michael Roth
            rs->ov_pending = true;
77 7868e26e Michael Roth
        } else {
78 7868e26e Michael Roth
            new_events |= G_IO_ERR;
79 7868e26e Michael Roth
        }
80 7868e26e Michael Roth
    }
81 7868e26e Michael Roth
82 7868e26e Michael Roth
out:
83 7868e26e Michael Roth
    /* dont block forever, iterate the main loop every once and a while */
84 7868e26e Michael Roth
    *timeout_ms = 500;
85 7868e26e Michael Roth
    /* if there's data in the read buffer, or another event is pending,
86 7868e26e Michael Roth
     * skip polling and issue user cb.
87 7868e26e Michael Roth
     */
88 7868e26e Michael Roth
    if (rs->pending) {
89 7868e26e Michael Roth
        new_events |= G_IO_IN;
90 7868e26e Michael Roth
    }
91 7868e26e Michael Roth
    c->pending_events |= new_events;
92 7868e26e Michael Roth
    return !!c->pending_events;
93 7868e26e Michael Roth
}
94 7868e26e Michael Roth
95 7868e26e Michael Roth
/*
96 7868e26e Michael Roth
 * Called by glib after an outstanding read request is completed.
97 7868e26e Michael Roth
 */
98 7868e26e Michael Roth
static gboolean ga_channel_check(GSource *source)
99 7868e26e Michael Roth
{
100 7868e26e Michael Roth
    GAWatch *watch = (GAWatch *)source;
101 7868e26e Michael Roth
    GAChannel *c = (GAChannel *)watch->channel;
102 7868e26e Michael Roth
    GAChannelReadState *rs = &c->rstate;
103 7868e26e Michael Roth
    DWORD count_read, error;
104 7868e26e Michael Roth
    BOOL success;
105 7868e26e Michael Roth
106 7868e26e Michael Roth
    GIOCondition new_events = 0;
107 7868e26e Michael Roth
108 7868e26e Michael Roth
    g_debug("check");
109 7868e26e Michael Roth
110 7868e26e Michael Roth
    /* failing this implies we issued a read that completed immediately,
111 7868e26e Michael Roth
     * yet no data was placed into the buffer (and thus we did not skip
112 7868e26e Michael Roth
     * polling). but since EOF is not obtainable until we retrieve an
113 7868e26e Michael Roth
     * overlapped result, it must be the case that there was data placed
114 7868e26e Michael Roth
     * into the buffer, or an error was generated by Readfile(). in either
115 7868e26e Michael Roth
     * case, we should've skipped the polling for this round.
116 7868e26e Michael Roth
     */
117 7868e26e Michael Roth
    g_assert(rs->ov_pending);
118 7868e26e Michael Roth
119 7868e26e Michael Roth
    success = GetOverlappedResult(c->handle, &rs->ov, &count_read, FALSE);
120 7868e26e Michael Roth
    if (success) {
121 7868e26e Michael Roth
        g_debug("thread: overlapped result, count_read: %d", (int)count_read);
122 7868e26e Michael Roth
        rs->pending += count_read;
123 7868e26e Michael Roth
        new_events |= G_IO_IN;
124 7868e26e Michael Roth
    } else {
125 7868e26e Michael Roth
        error = GetLastError();
126 7868e26e Michael Roth
        if (error == 0 || error == ERROR_HANDLE_EOF ||
127 7868e26e Michael Roth
            error == ERROR_NO_SYSTEM_RESOURCES ||
128 7868e26e Michael Roth
            error == ERROR_OPERATION_ABORTED) {
129 7868e26e Michael Roth
            /* note: On WinXP SP3 with rhel6ga virtio-win-1.1.16 vioser drivers,
130 7868e26e Michael Roth
             * ENSR seems to be synonymous with when we'd normally expect
131 7868e26e Michael Roth
             * ERROR_HANDLE_EOF. So treat it as such. Microsoft's
132 7868e26e Michael Roth
             * recommendation for ERROR_NO_SYSTEM_RESOURCES is to
133 7868e26e Michael Roth
             * retry the read, so this happens to work out anyway. On newer
134 7868e26e Michael Roth
             * virtio-win driver, this seems to be replaced with EOA, so
135 7868e26e Michael Roth
             * handle that in the same fashion.
136 7868e26e Michael Roth
             */
137 7868e26e Michael Roth
            new_events |= G_IO_HUP;
138 7868e26e Michael Roth
        } else if (error != ERROR_IO_INCOMPLETE) {
139 7868e26e Michael Roth
            g_critical("error retrieving overlapped result: %d", (int)error);
140 7868e26e Michael Roth
            new_events |= G_IO_ERR;
141 7868e26e Michael Roth
        }
142 7868e26e Michael Roth
    }
143 7868e26e Michael Roth
144 7868e26e Michael Roth
    if (new_events) {
145 7868e26e Michael Roth
        rs->ov_pending = 0;
146 7868e26e Michael Roth
    }
147 7868e26e Michael Roth
    c->pending_events |= new_events;
148 7868e26e Michael Roth
149 7868e26e Michael Roth
    return !!c->pending_events;
150 7868e26e Michael Roth
}
151 7868e26e Michael Roth
152 7868e26e Michael Roth
/*
153 7868e26e Michael Roth
 * Called by glib after either prepare or check routines signal readiness
154 7868e26e Michael Roth
 */
155 7868e26e Michael Roth
static gboolean ga_channel_dispatch(GSource *source, GSourceFunc unused,
156 7868e26e Michael Roth
                                    gpointer user_data)
157 7868e26e Michael Roth
{
158 7868e26e Michael Roth
    GAWatch *watch = (GAWatch *)source;
159 7868e26e Michael Roth
    GAChannel *c = (GAChannel *)watch->channel;
160 7868e26e Michael Roth
    GAChannelReadState *rs = &c->rstate;
161 7868e26e Michael Roth
    gboolean success;
162 7868e26e Michael Roth
163 7868e26e Michael Roth
    g_debug("dispatch");
164 7868e26e Michael Roth
    success = c->cb(watch->pollfd.revents, c->user_data);
165 7868e26e Michael Roth
166 7868e26e Michael Roth
    if (c->pending_events & G_IO_ERR) {
167 7868e26e Michael Roth
        g_critical("channel error, removing source");
168 7868e26e Michael Roth
        return false;
169 7868e26e Michael Roth
    }
170 7868e26e Michael Roth
171 7868e26e Michael Roth
    /* TODO: replace rs->pending with watch->revents */
172 7868e26e Michael Roth
    c->pending_events &= ~G_IO_HUP;
173 7868e26e Michael Roth
    if (!rs->pending) {
174 7868e26e Michael Roth
        c->pending_events &= ~G_IO_IN;
175 7868e26e Michael Roth
    } else {
176 7868e26e Michael Roth
        c->pending_events = 0;
177 7868e26e Michael Roth
    }
178 7868e26e Michael Roth
    return success;
179 7868e26e Michael Roth
}
180 7868e26e Michael Roth
181 7868e26e Michael Roth
static void ga_channel_finalize(GSource *source)
182 7868e26e Michael Roth
{
183 7868e26e Michael Roth
    g_debug("finalize");
184 7868e26e Michael Roth
}
185 7868e26e Michael Roth
186 7868e26e Michael Roth
GSourceFuncs ga_channel_watch_funcs = {
187 7868e26e Michael Roth
    ga_channel_prepare,
188 7868e26e Michael Roth
    ga_channel_check,
189 7868e26e Michael Roth
    ga_channel_dispatch,
190 7868e26e Michael Roth
    ga_channel_finalize
191 7868e26e Michael Roth
};
192 7868e26e Michael Roth
193 7868e26e Michael Roth
static GSource *ga_channel_create_watch(GAChannel *c)
194 7868e26e Michael Roth
{
195 7868e26e Michael Roth
    GSource *source = g_source_new(&ga_channel_watch_funcs, sizeof(GAWatch));
196 7868e26e Michael Roth
    GAWatch *watch = (GAWatch *)source;
197 7868e26e Michael Roth
198 7868e26e Michael Roth
    watch->channel = c;
199 7868e26e Michael Roth
    watch->pollfd.fd = (gintptr) c->rstate.ov.hEvent;
200 7868e26e Michael Roth
    g_source_add_poll(source, &watch->pollfd);
201 7868e26e Michael Roth
202 7868e26e Michael Roth
    return source;
203 7868e26e Michael Roth
}
204 7868e26e Michael Roth
205 7868e26e Michael Roth
GIOStatus ga_channel_read(GAChannel *c, char *buf, size_t size, gsize *count)
206 7868e26e Michael Roth
{
207 7868e26e Michael Roth
    GAChannelReadState *rs = &c->rstate;
208 7868e26e Michael Roth
    GIOStatus status;
209 7868e26e Michael Roth
    size_t to_read = 0;
210 7868e26e Michael Roth
211 7868e26e Michael Roth
    if (c->pending_events & G_IO_ERR) {
212 7868e26e Michael Roth
        return G_IO_STATUS_ERROR;
213 7868e26e Michael Roth
    }
214 7868e26e Michael Roth
215 7868e26e Michael Roth
    *count = to_read = MIN(size, rs->pending);
216 7868e26e Michael Roth
    if (to_read) {
217 7868e26e Michael Roth
        memcpy(buf, rs->buf + rs->cur, to_read);
218 7868e26e Michael Roth
        rs->cur += to_read;
219 7868e26e Michael Roth
        rs->pending -= to_read;
220 7868e26e Michael Roth
        status = G_IO_STATUS_NORMAL;
221 7868e26e Michael Roth
    } else {
222 7868e26e Michael Roth
        status = G_IO_STATUS_AGAIN;
223 7868e26e Michael Roth
    }
224 7868e26e Michael Roth
225 7868e26e Michael Roth
    return status;
226 7868e26e Michael Roth
}
227 7868e26e Michael Roth
228 7868e26e Michael Roth
static GIOStatus ga_channel_write(GAChannel *c, const char *buf, size_t size,
229 7868e26e Michael Roth
                                  size_t *count)
230 7868e26e Michael Roth
{
231 7868e26e Michael Roth
    GIOStatus status;
232 7868e26e Michael Roth
    OVERLAPPED ov = {0};
233 7868e26e Michael Roth
    BOOL ret;
234 7868e26e Michael Roth
    DWORD written;
235 7868e26e Michael Roth
236 7868e26e Michael Roth
    ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
237 7868e26e Michael Roth
    ret = WriteFile(c->handle, buf, size, &written, &ov);
238 7868e26e Michael Roth
    if (!ret) {
239 7868e26e Michael Roth
        if (GetLastError() == ERROR_IO_PENDING) {
240 7868e26e Michael Roth
            /* write is pending */
241 7868e26e Michael Roth
            ret = GetOverlappedResult(c->handle, &ov, &written, TRUE);
242 7868e26e Michael Roth
            if (!ret) {
243 7868e26e Michael Roth
                if (!GetLastError()) {
244 7868e26e Michael Roth
                    status = G_IO_STATUS_AGAIN;
245 7868e26e Michael Roth
                } else {
246 7868e26e Michael Roth
                    status = G_IO_STATUS_ERROR;
247 7868e26e Michael Roth
                }
248 7868e26e Michael Roth
            } else {
249 7868e26e Michael Roth
                /* write is complete */
250 7868e26e Michael Roth
                status = G_IO_STATUS_NORMAL;
251 7868e26e Michael Roth
                *count = written;
252 7868e26e Michael Roth
            }
253 7868e26e Michael Roth
        } else {
254 7868e26e Michael Roth
            status = G_IO_STATUS_ERROR;
255 7868e26e Michael Roth
        }
256 7868e26e Michael Roth
    } else {
257 7868e26e Michael Roth
        /* write returned immediately */
258 7868e26e Michael Roth
        status = G_IO_STATUS_NORMAL;
259 7868e26e Michael Roth
        *count = written;
260 7868e26e Michael Roth
    }
261 7868e26e Michael Roth
262 b71706d1 Jeff Cody
    if (ov.hEvent) {
263 b71706d1 Jeff Cody
        CloseHandle(ov.hEvent);
264 b71706d1 Jeff Cody
        ov.hEvent = NULL;
265 b71706d1 Jeff Cody
    }
266 7868e26e Michael Roth
    return status;
267 7868e26e Michael Roth
}
268 7868e26e Michael Roth
269 7868e26e Michael Roth
GIOStatus ga_channel_write_all(GAChannel *c, const char *buf, size_t size)
270 7868e26e Michael Roth
{
271 7868e26e Michael Roth
    GIOStatus status = G_IO_STATUS_NORMAL;;
272 7868e26e Michael Roth
    size_t count;
273 7868e26e Michael Roth
274 7868e26e Michael Roth
    while (size) {
275 7868e26e Michael Roth
        status = ga_channel_write(c, buf, size, &count);
276 7868e26e Michael Roth
        if (status == G_IO_STATUS_NORMAL) {
277 7868e26e Michael Roth
            size -= count;
278 7868e26e Michael Roth
            buf += count;
279 7868e26e Michael Roth
        } else if (status != G_IO_STATUS_AGAIN) {
280 7868e26e Michael Roth
            break;
281 7868e26e Michael Roth
        }
282 7868e26e Michael Roth
    }
283 7868e26e Michael Roth
284 7868e26e Michael Roth
    return status;
285 7868e26e Michael Roth
}
286 7868e26e Michael Roth
287 7868e26e Michael Roth
static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method,
288 7868e26e Michael Roth
                                const gchar *path)
289 7868e26e Michael Roth
{
290 7868e26e Michael Roth
    if (!method == GA_CHANNEL_VIRTIO_SERIAL) {
291 7868e26e Michael Roth
        g_critical("unsupported communication method");
292 7868e26e Michael Roth
        return false;
293 7868e26e Michael Roth
    }
294 7868e26e Michael Roth
295 7868e26e Michael Roth
    c->handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
296 7868e26e Michael Roth
                           OPEN_EXISTING,
297 7868e26e Michael Roth
                           FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);
298 7868e26e Michael Roth
    if (c->handle == INVALID_HANDLE_VALUE) {
299 7868e26e Michael Roth
        g_critical("error opening path");
300 7868e26e Michael Roth
        return false;
301 7868e26e Michael Roth
    }
302 7868e26e Michael Roth
303 7868e26e Michael Roth
    return true;
304 7868e26e Michael Roth
}
305 7868e26e Michael Roth
306 7868e26e Michael Roth
GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
307 7868e26e Michael Roth
                          GAChannelCallback cb, gpointer opaque)
308 7868e26e Michael Roth
{
309 7868e26e Michael Roth
    GAChannel *c = g_malloc0(sizeof(GAChannel));
310 7868e26e Michael Roth
    SECURITY_ATTRIBUTES sec_attrs;
311 7868e26e Michael Roth
312 7868e26e Michael Roth
    if (!ga_channel_open(c, method, path)) {
313 7868e26e Michael Roth
        g_critical("error opening channel");
314 7868e26e Michael Roth
        g_free(c);
315 7868e26e Michael Roth
        return NULL;
316 7868e26e Michael Roth
    }
317 7868e26e Michael Roth
318 7868e26e Michael Roth
    c->cb = cb;
319 7868e26e Michael Roth
    c->user_data = opaque;
320 7868e26e Michael Roth
321 7868e26e Michael Roth
    sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
322 7868e26e Michael Roth
    sec_attrs.lpSecurityDescriptor = NULL;
323 7868e26e Michael Roth
    sec_attrs.bInheritHandle = false;
324 7868e26e Michael Roth
325 7868e26e Michael Roth
    c->rstate.buf_size = QGA_READ_COUNT_DEFAULT;
326 7868e26e Michael Roth
    c->rstate.buf = g_malloc(QGA_READ_COUNT_DEFAULT);
327 7868e26e Michael Roth
    c->rstate.ov.hEvent = CreateEvent(&sec_attrs, FALSE, FALSE, NULL);
328 7868e26e Michael Roth
329 7868e26e Michael Roth
    c->source = ga_channel_create_watch(c);
330 7868e26e Michael Roth
    g_source_attach(c->source, NULL);
331 7868e26e Michael Roth
    return c;
332 7868e26e Michael Roth
}
333 7868e26e Michael Roth
334 7868e26e Michael Roth
void ga_channel_free(GAChannel *c)
335 7868e26e Michael Roth
{
336 7868e26e Michael Roth
    if (c->source) {
337 7868e26e Michael Roth
        g_source_destroy(c->source);
338 7868e26e Michael Roth
    }
339 7868e26e Michael Roth
    if (c->rstate.ov.hEvent) {
340 7868e26e Michael Roth
        CloseHandle(c->rstate.ov.hEvent);
341 7868e26e Michael Roth
    }
342 7868e26e Michael Roth
    g_free(c->rstate.buf);
343 7868e26e Michael Roth
    g_free(c);
344 7868e26e Michael Roth
}