diff options
Diffstat (limited to 'windows/cliloop.c')
-rw-r--r-- | windows/cliloop.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/windows/cliloop.c b/windows/cliloop.c new file mode 100644 index 00000000..eced54ca --- /dev/null +++ b/windows/cliloop.c @@ -0,0 +1,134 @@ +#include "putty.h" + +void cli_main_loop(cliloop_pre_t pre, cliloop_post_t post, void *ctx) +{ + SOCKET *sklist = NULL; + size_t skcount = 0, sksize = 0; + unsigned long now, next, then; + now = GETTICKCOUNT(); + + while (true) { + DWORD n; + DWORD ticks; + + const HANDLE *extra_handles = NULL; + size_t n_extra_handles = 0; + if (!pre(ctx, &extra_handles, &n_extra_handles)) + break; + + if (toplevel_callback_pending()) { + ticks = 0; + next = now; + } else if (run_timers(now, &next)) { + then = now; + now = GETTICKCOUNT(); + if (now - then > next - then) + ticks = 0; + else + ticks = next - now; + } else { + ticks = INFINITE; + /* no need to initialise next here because we can never + * get WAIT_TIMEOUT */ + } + + HandleWaitList *hwl = get_handle_wait_list(); + size_t winselcli_index = -(size_t)1; + size_t extra_base = hwl->nhandles; + if (winselcli_event != INVALID_HANDLE_VALUE) { + assert(extra_base < MAXIMUM_WAIT_OBJECTS); + winselcli_index = extra_base++; + hwl->handles[winselcli_index] = winselcli_event; + } + size_t total_handles = extra_base + n_extra_handles; + assert(total_handles < MAXIMUM_WAIT_OBJECTS); + for (size_t i = 0; i < n_extra_handles; i++) + hwl->handles[extra_base + i] = extra_handles[i]; + + n = WaitForMultipleObjects(total_handles, hwl->handles, false, ticks); + + size_t extra_handle_index = n_extra_handles; + + if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)hwl->nhandles) { + handle_wait_activate(hwl, n - WAIT_OBJECT_0); + } else if (winselcli_event != INVALID_HANDLE_VALUE && + n == WAIT_OBJECT_0 + winselcli_index) { + WSANETWORKEVENTS things; + SOCKET socket; + int i, socketstate; + + /* + * We must not call select_result() for any socket + * until we have finished enumerating within the tree. + * This is because select_result() may close the socket + * and modify the tree. + */ + /* Count the active sockets. */ + i = 0; + for (socket = first_socket(&socketstate); + socket != INVALID_SOCKET; + socket = next_socket(&socketstate)) i++; + + /* Expand the buffer if necessary. */ + sgrowarray(sklist, sksize, i); + + /* Retrieve the sockets into sklist. */ + skcount = 0; + for (socket = first_socket(&socketstate); + socket != INVALID_SOCKET; + socket = next_socket(&socketstate)) { + sklist[skcount++] = socket; + } + + /* Now we're done enumerating; go through the list. */ + for (i = 0; i < skcount; i++) { + WPARAM wp; + socket = sklist[i]; + wp = (WPARAM) socket; + if (!p_WSAEnumNetworkEvents(socket, NULL, &things)) { + static const struct { int bit, mask; } eventtypes[] = { + {FD_CONNECT_BIT, FD_CONNECT}, + {FD_READ_BIT, FD_READ}, + {FD_CLOSE_BIT, FD_CLOSE}, + {FD_OOB_BIT, FD_OOB}, + {FD_WRITE_BIT, FD_WRITE}, + {FD_ACCEPT_BIT, FD_ACCEPT}, + }; + int e; + + noise_ultralight(NOISE_SOURCE_IOID, socket); + + for (e = 0; e < lenof(eventtypes); e++) + if (things.lNetworkEvents & eventtypes[e].mask) { + LPARAM lp; + int err = things.iErrorCode[eventtypes[e].bit]; + lp = WSAMAKESELECTREPLY(eventtypes[e].mask, err); + select_result(wp, lp); + } + } + } + } else if (n >= WAIT_OBJECT_0 + extra_base && + n < WAIT_OBJECT_0 + extra_base + n_extra_handles) { + extra_handle_index = n - (WAIT_OBJECT_0 + extra_base); + } + + run_toplevel_callbacks(); + + if (n == WAIT_TIMEOUT) { + now = next; + } else { + now = GETTICKCOUNT(); + } + + handle_wait_list_free(hwl); + + if (!post(ctx, extra_handle_index)) + break; + } + + sfree(sklist); +} + +bool cliloop_null_pre(void *vctx, const HANDLE **eh, size_t *neh) +{ return true; } +bool cliloop_null_post(void *vctx, size_t ehi) { return true; } |