From bd5c957e5bd0f850ab30c6b1ab94bfbbabe9f006 Mon Sep 17 00:00:00 2001
From: Simon Tatham <anakin@pobox.com>
Date: Sat, 21 Dec 2019 13:31:02 +0000
Subject: [PATCH] winsftp.c: avoid creating multiple netevents.
The do_select function is called with a boolean parameter indicating
whether we're supposed to start or stop paying attention to network
activity on a given socket. So if we freeze and unfreeze the socket in
mid-session because of backlog, we'll call do_select(s, false) to
freeze it, and do_select(s, true) to unfreeze it.
But the implementation of do_select in the Windows SFTP code predated
the rigorous handling of socket backlogs, so it assumed that
do_select(s, true) would only be called at initialisation time, i.e.
only once, and therefore that it was safe to use that flag as a cue to
set up the Windows event object to associate with socket activity.
Hence, every time the socket was frozen and unfrozen, we would create
a new netevent at unfreeze time, leaking the old one.
I think perhaps part of the reason why that was hard to figure out was
that the boolean parameter was called 'startup' rather than 'enable'.
To make it less confusing the next time I read this code, I've also
renamed it, and while I was at it, adjusted another related comment.
---
windows/window.c | 4 ++--
windows/winplink.c | 4 ++--
windows/winsftp.c | 14 +++++++++-----
windows/winstuff.h | 2 +-
4 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/windows/window.c b/windows/window.c
index f9e09aa3..a17a9854 100644
a
|
b
|
void cleanup_exit(int code)
|
1026 | 1026 | /* |
1027 | 1027 | * Set up, or shut down, an AsyncSelect. Called from winnet.c. |
1028 | 1028 | */ |
1029 | | char *do_select(SOCKET skt, bool startup) |
| 1029 | char *do_select(SOCKET skt, bool enable) |
1030 | 1030 | { |
1031 | 1031 | int msg, events; |
1032 | | if (startup) { |
| 1032 | if (enable) { |
1033 | 1033 | msg = WM_NETEVENT; |
1034 | 1034 | events = (FD_CONNECT | FD_READ | FD_WRITE | |
1035 | 1035 | FD_OOB | FD_CLOSE | FD_ACCEPT); |
diff --git a/windows/winplink.c b/windows/winplink.c
index dce5691f..39ca8fb5 100644
a
|
b
|
static void version(void)
|
190 | 190 | exit(0); |
191 | 191 | } |
192 | 192 | |
193 | | char *do_select(SOCKET skt, bool startup) |
| 193 | char *do_select(SOCKET skt, bool enable) |
194 | 194 | { |
195 | 195 | int events; |
196 | | if (startup) { |
| 196 | if (enable) { |
197 | 197 | events = (FD_CONNECT | FD_READ | FD_WRITE | |
198 | 198 | FD_OOB | FD_CLOSE | FD_ACCEPT); |
199 | 199 | } else { |
diff --git a/windows/winsftp.c b/windows/winsftp.c
index b120890c..91c3f2fd 100644
a
|
b
|
char *dir_file_cat(const char *dir, const char *file)
|
467 | 467 | */ |
468 | 468 | static SOCKET sftp_ssh_socket = INVALID_SOCKET; |
469 | 469 | static HANDLE netevent = INVALID_HANDLE_VALUE; |
470 | | char *do_select(SOCKET skt, bool startup) |
| 470 | char *do_select(SOCKET skt, bool enable) |
471 | 471 | { |
472 | 472 | int events; |
473 | | if (startup) |
| 473 | if (enable) |
474 | 474 | sftp_ssh_socket = skt; |
475 | 475 | else |
476 | 476 | sftp_ssh_socket = INVALID_SOCKET; |
477 | 477 | |
| 478 | if (netevent == INVALID_HANDLE_VALUE) |
| 479 | netevent = CreateEvent(NULL, false, false, NULL); |
| 480 | |
478 | 481 | if (p_WSAEventSelect) { |
479 | | if (startup) { |
| 482 | if (enable) { |
480 | 483 | events = (FD_CONNECT | FD_READ | FD_WRITE | |
481 | 484 | FD_OOB | FD_CLOSE | FD_ACCEPT); |
482 | | netevent = CreateEvent(NULL, false, false, NULL); |
483 | 485 | } else { |
484 | 486 | events = 0; |
485 | 487 | } |
… |
… |
char *ssh_sftp_get_cmdline(const char *prompt, bool no_fds_ok)
|
732 | 734 | do { |
733 | 735 | ret = do_eventsel_loop(ctx->event); |
734 | 736 | |
735 | | /* Error return can only occur if netevent==NULL, and it ain't. */ |
| 737 | /* do_eventsel_loop can't return an error (unlike |
| 738 | * ssh_sftp_loop_iteration, which can return -1 if select goes |
| 739 | * wrong or if the socket doesn't exist). */ |
736 | 740 | assert(ret >= 0); |
737 | 741 | } while (ret == 0); |
738 | 742 | |
diff --git a/windows/winstuff.h b/windows/winstuff.h
index 0b191d54..c189c37a 100644
a
|
b
|
DECL_WINDOWS_FUNCTION(GLOBAL, int, select,
|
350 | 350 | * Provided by each client of winnet.c, and called by winnet.c to turn |
351 | 351 | * on or off WSA*Select for a given socket. |
352 | 352 | */ |
353 | | char *do_select(SOCKET skt, bool startup); |
| 353 | char *do_select(SOCKET skt, bool enable); |
354 | 354 | |
355 | 355 | /* |
356 | 356 | * Network-subsystem-related functions provided in other Windows modules. |