From: Simon Tatham Date: Thu, 16 Feb 2017 20:26:58 +0000 (+0000) Subject: Implement deferred closing of Windows handle-sockets. X-Git-Tag: 0.68~6 X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=commitdiff_plain;h=92d855d0fe9b327f3881170d7663bcc5ec8f8d20;p=PuTTY.git Implement deferred closing of Windows handle-sockets. When a handle socket is in THAWING state and handle_socket_unfreeze is gradually passing the backlogged data on to the plug, the plug might suddenly turn round and close the socket in the course of handling plug_receive(), which means that handle_socket_unfreeze had better be careful not to have had everything vanish out from under it when that call returns. To solve this, I've added a 'deferred close' flag which handle_socket_unfreeze can set around its call to plug_receive, and handle_socket_close will detect that and not actually free the socket, instead leaving that for handle_socket_unfreeze to do under its own control. --- diff --git a/windows/winhsock.c b/windows/winhsock.c index 7fe02f63..8acb82be 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -42,6 +42,8 @@ struct Socket_handle_tag { /* Data received from stderr_H, if we have one. */ bufchain stderrdata; + int defer_close, deferred_close; /* in case of re-entrance */ + char *error; Plug plug; @@ -109,6 +111,11 @@ static void sk_handle_close(Socket s) { Handle_Socket ps = (Handle_Socket) s; + if (ps->defer_close) { + ps->deferred_close = TRUE; + return; + } + handle_free(ps->send_h); handle_free(ps->recv_h); CloseHandle(ps->send_H); @@ -169,10 +176,17 @@ static void handle_socket_unfreeze(void *psv) assert(len > 0); /* - * Hand it off to the plug. + * Hand it off to the plug. Be careful of re-entrance - that might + * have the effect of trying to close this socket. */ + ps->defer_close = TRUE; new_backlog = plug_receive(ps->plug, 0, data, len); bufchain_consume(&ps->inputdata, len); + ps->defer_close = FALSE; + if (ps->deferred_close) { + sk_handle_close(ps); + return; + } if (bufchain_size(&ps->inputdata) > 0) { /* @@ -310,5 +324,7 @@ Socket make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, ret->stderr_h = handle_input_new(ret->stderr_H, handle_stderr, ret, flags); + ret->defer_close = ret->deferred_close = FALSE; + return (Socket) ret; }