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 COMMTIMEOUTS comTimeOut = {0}; 291 gchar newpath[MAXPATHLEN] = {0}; 292 comTimeOut.ReadIntervalTimeout = 1; 293 294 if (method != GA_CHANNEL_VIRTIO_SERIAL && method != GA_CHANNEL_ISA_SERIAL) { 295 g_critical("unsupported communication method"); 296 return false; 297 } 298 299 if (method == GA_CHANNEL_ISA_SERIAL){ 300 snprintf(newpath, sizeof(newpath), "\\\\.\\%s", path); 301 }else { 302 g_strlcpy(newpath, path, sizeof(newpath)); 303 } 304 305 c->handle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, 306 OPEN_EXISTING, 307 FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); 308 if (c->handle == INVALID_HANDLE_VALUE) { 309 g_critical("error opening path %s", newpath); 310 return false; 311 } 312 313 if (method == GA_CHANNEL_ISA_SERIAL && !SetCommTimeouts(c->handle,&comTimeOut)) { 314 g_critical("error setting timeout for com port: %lu",GetLastError()); 315 CloseHandle(c->handle); 316 return false; 317 } 318 319 return true; 320 } 321 322 GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path, 323 GAChannelCallback cb, gpointer opaque) 324 { 325 GAChannel *c = g_malloc0(sizeof(GAChannel)); 326 SECURITY_ATTRIBUTES sec_attrs; 327 328 if (!ga_channel_open(c, method, path)) { 329 g_critical("error opening channel"); 330 g_free(c); 331 return NULL; 332 } 333 334 c->cb = cb; 335 c->user_data = opaque; 336 337 sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES); 338 sec_attrs.lpSecurityDescriptor = NULL; 339 sec_attrs.bInheritHandle = false; 340 341 c->rstate.buf_size = QGA_READ_COUNT_DEFAULT; 342 c->rstate.buf = g_malloc(QGA_READ_COUNT_DEFAULT); 343 c->rstate.ov.hEvent = CreateEvent(&sec_attrs, FALSE, FALSE, NULL); 344 345 c->source = ga_channel_create_watch(c); 346 g_source_attach(c->source, NULL); 347 return c; 348 } 349 350 void ga_channel_free(GAChannel *c) 351 { 352 if (c->source) { 353 g_source_destroy(c->source); 354 } 355 if (c->rstate.ov.hEvent) { 356 CloseHandle(c->rstate.ov.hEvent); 357 } 358 g_free(c->rstate.buf); 359 g_free(c); 360 } 361