diff --git a/Recipe b/Recipe index 7c251d30..14e26b3d 100644 --- a/Recipe +++ b/Recipe @@ -335,11 +335,11 @@ putty : [G] GUITERM NONSSH WINSSH W_BE_ALL WINMISC winx11 putty.res LIBS puttytel : [G] GUITERM NONSSH W_BE_NOSSH WINMISC puttytel.res nogss LIBS plink : [C] winplink wincons NONSSH WINSSH W_BE_ALL logging WINMISC + winx11 plink.res winnojmp sessprep noterm winnohlp winselcli - + clicons LIBS + + clicons wincliloop LIBS pscp : [C] pscp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC - + pscp.res winnojmp winnohlp winselcli clicons LIBS + + pscp.res winnojmp winnohlp winselcli clicons wincliloop LIBS psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC - + psftp.res winnojmp winnohlp winselcli clicons LIBS + + psftp.res winnojmp winnohlp winselcli clicons wincliloop LIBS pageant : [G] winpgnt pageant sshrsa sshpubk sshdes ARITH sshmd5 version + tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256 diff --git a/windows/wincliloop.c b/windows/wincliloop.c new file mode 100644 index 00000000..0f1f5cd9 --- /dev/null +++ b/windows/wincliloop.c @@ -0,0 +1,129 @@ +#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) { + int nhandles; + HANDLE *handles; + int 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 */ + } + + handles = handle_get_events(&nhandles); + size_t winselcli_index = nhandles; + size_t extra_base = winselcli_index + 1; + size_t total_handles = extra_base + n_extra_handles; + handles = sresize(handles, total_handles, HANDLE); + handles[winselcli_index] = winselcli_event; + for (size_t i = 0; i < n_extra_handles; i++) + handles[extra_base + i] = extra_handles[i]; + + n = WaitForMultipleObjects(total_handles, handles, false, ticks); + + size_t extra_handle_index = n_extra_handles; + + if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) { + handle_got_event(handles[n - WAIT_OBJECT_0]); + } else if (n == WAIT_OBJECT_0 + nhandles) { + 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(); + } + + sfree(handles); + + if (!post(ctx, extra_handle_index)) + break; + } +} + +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; } diff --git a/windows/winplink.c b/windows/winplink.c index 47f27c58..22f57cf0 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -231,23 +231,43 @@ const unsigned cmdline_tooltype = TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX | TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD; +static bool sending; + +static bool plink_mainloop_pre(void *vctx, const HANDLE **extra_handles, + size_t *n_extra_handles) +{ + if (!sending && backend_sendok(backend)) { + stdin_handle = handle_input_new(inhandle, stdin_gotdata, NULL, + 0); + sending = true; + } + + return true; +} + +static bool plink_mainloop_post(void *vctx, size_t extra_handle_index) +{ + if (sending) + handle_unthrottle(stdin_handle, backend_sendbuffer(backend)); + + if (!backend_connected(backend) && + handle_backlog(stdout_handle) + handle_backlog(stderr_handle) == 0) + return false; /* we closed the connection */ + + return true; +} + int main(int argc, char **argv) { - bool sending; - SOCKET *sklist; - size_t skcount, sksize; int exitcode; bool errors; bool use_subsystem = false; bool just_test_share_exists = false; enum TriState sanitise_stdout = AUTO, sanitise_stderr = AUTO; - unsigned long now, next, then; const struct BackendVtable *vt; dll_hijacking_protection(); - sklist = NULL; - skcount = sksize = 0; /* * Initialise port and protocol to sensible defaults. (These * will be overridden by more or less anything.) @@ -487,116 +507,8 @@ int main(int argc, char **argv) sending = false; - now = GETTICKCOUNT(); + cli_main_loop(plink_mainloop_pre, plink_mainloop_post, NULL); - while (1) { - int nhandles; - HANDLE *handles; - int n; - DWORD ticks; - - if (!sending && backend_sendok(backend)) { - stdin_handle = handle_input_new(inhandle, stdin_gotdata, NULL, - 0); - sending = true; - } - - 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 */ - } - - handles = handle_get_events(&nhandles); - handles = sresize(handles, nhandles+1, HANDLE); - handles[nhandles] = winselcli_event; - n = WaitForMultipleObjects(nhandles+1, handles, false, ticks); - if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) { - handle_got_event(handles[n - WAIT_OBJECT_0]); - } else if (n == WAIT_OBJECT_0 + nhandles) { - 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); - } - } - } - } - - run_toplevel_callbacks(); - - if (n == WAIT_TIMEOUT) { - now = next; - } else { - now = GETTICKCOUNT(); - } - - sfree(handles); - - if (sending) - handle_unthrottle(stdin_handle, backend_sendbuffer(backend)); - - if (!backend_connected(backend) && - handle_backlog(stdout_handle) + handle_backlog(stderr_handle) == 0) - break; /* we closed the connection */ - } exitcode = backend_exitcode(backend); if (exitcode < 0) { fprintf(stderr, "Remote process exit code unavailable\n"); diff --git a/windows/winsftp.c b/windows/winsftp.c index af4980bd..0c695d2e 100644 --- a/windows/winsftp.c +++ b/windows/winsftp.c @@ -461,123 +461,39 @@ char *dir_file_cat(const char *dir, const char *file) /* ---------------------------------------------------------------------- * Platform-specific network handling. */ +struct winsftp_cliloop_ctx { + HANDLE other_event; + int toret; +}; +static bool winsftp_cliloop_pre(void *vctx, const HANDLE **extra_handles, + size_t *n_extra_handles) +{ + struct winsftp_cliloop_ctx *ctx = (struct winsftp_cliloop_ctx *)vctx; + if (ctx->other_event != INVALID_HANDLE_VALUE) { + *extra_handles = &ctx->other_event; + *n_extra_handles = 1; + } + + return true; +} +static bool winsftp_cliloop_post(void *vctx, size_t extra_handle_index) +{ + struct winsftp_cliloop_ctx *ctx = (struct winsftp_cliloop_ctx *)vctx; + + if (ctx->other_event != INVALID_HANDLE_VALUE && + extra_handle_index == 0) + ctx->toret = 1; /* other_event was set */ + + return false; /* always run only one loop iteration */ +} int do_eventsel_loop(HANDLE other_event) { - int n, nhandles, nallhandles, netindex, otherindex; - unsigned long next, then; - long ticks; - HANDLE *handles; - SOCKET *sklist; - int skcount; - unsigned long now = GETTICKCOUNT(); - - 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 */ - } - - handles = handle_get_events(&nhandles); - handles = sresize(handles, nhandles+2, HANDLE); - nallhandles = nhandles; - - if (winselcli_event != INVALID_HANDLE_VALUE) - handles[netindex = nallhandles++] = winselcli_event; - else - netindex = -1; - if (other_event != INVALID_HANDLE_VALUE) - handles[otherindex = nallhandles++] = other_event; - else - otherindex = -1; - - n = WaitForMultipleObjects(nallhandles, handles, false, ticks); - - if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) { - handle_got_event(handles[n - WAIT_OBJECT_0]); - } else if (netindex >= 0 && n == WAIT_OBJECT_0 + netindex) { - 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. */ - sklist = snewn(i, SOCKET); - - /* 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); - } - } - } - - sfree(sklist); - } - - sfree(handles); - - run_toplevel_callbacks(); - - if (n == WAIT_TIMEOUT) { - now = next; - } else { - now = GETTICKCOUNT(); - } - - if (otherindex >= 0 && n == WAIT_OBJECT_0 + otherindex) - return 1; - - return 0; + struct winsftp_cliloop_ctx ctx[1]; + ctx->other_event = other_event; + ctx->toret = 0; + cli_main_loop(winsftp_cliloop_pre, winsftp_cliloop_post, ctx); + return ctx->toret; } /* diff --git a/windows/winstuff.h b/windows/winstuff.h index 4d31920e..f837a4b0 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -686,4 +686,12 @@ char *get_jumplist_registry_entries(void); /* In winmisc.c */ char *registry_get_string(HKEY root, const char *path, const char *leaf); +/* In wincliloop.c */ +typedef bool (*cliloop_pre_t)(void *vctx, const HANDLE **extra_handles, + size_t *n_extra_handles); +typedef bool (*cliloop_post_t)(void *vctx, size_t extra_handle_index); +void cli_main_loop(cliloop_pre_t pre, cliloop_post_t post, void *ctx); +bool cliloop_null_pre(void *vctx, const HANDLE **, size_t *); +bool cliloop_null_post(void *vctx, size_t); + #endif