channel-win32.c (10334B)
1#include "qemu/osdep.h" 2#include <windows.h> 3#include <io.h> 4#include "guest-agent-core.h" 5#include "channel.h" 6 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: 79 /* don't block forever, iterate the main loop every once in a while */ 80 *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 258 if (ov.hEvent) { 259 CloseHandle(ov.hEvent); 260 ov.hEvent = NULL; 261 } 262 return status; 263} 264 265GIOStatus ga_channel_write_all(GAChannel *c, const char *buf, size_t size) 266{ 267 GIOStatus status = G_IO_STATUS_NORMAL; 268 size_t count = 0; 269 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{ 286 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) { 291 g_critical("unsupported communication method"); 292 return false; 293 } 294 295 if (method == GA_CHANNEL_ISA_SERIAL) { 296 snprintf(newpath, sizeof(newpath), "\\\\.\\%s", path); 297 } else { 298 g_strlcpy(newpath, path, sizeof(newpath)); 299 } 300 301 c->handle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, 302 OPEN_EXISTING, 303 FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); 304 if (c->handle == INVALID_HANDLE_VALUE) { 305 g_autofree gchar *emsg = g_win32_error_message(GetLastError()); 306 g_critical("error opening path %s: %s", newpath, emsg); 307 return false; 308 } 309 310 if (method == GA_CHANNEL_ISA_SERIAL 311 && !SetCommTimeouts(c->handle, &comTimeOut)) { 312 g_autofree gchar *emsg = g_win32_error_message(GetLastError()); 313 g_critical("error setting timeout for com port: %s", emsg); 314 CloseHandle(c->handle); 315 return false; 316 } 317 318 return true; 319} 320 321GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path, 322 int listen_fd, GAChannelCallback cb, gpointer opaque) 323{ 324 GAChannel *c = g_new0(GAChannel, 1); 325 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}