]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Implement deferred closing of Windows handle-sockets.
authorSimon Tatham <anakin@pobox.com>
Thu, 16 Feb 2017 20:26:58 +0000 (20:26 +0000)
committerSimon Tatham <anakin@pobox.com>
Fri, 17 Feb 2017 08:40:57 +0000 (08:40 +0000)
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.

windows/winhsock.c

index 7fe02f634d789aad52491cd7b50c7899b1fc5fee..8acb82be61b5493195c26e1600d03b62878a295e 100644 (file)
@@ -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;
 }