Replace the type-checking COMPTR macro with my current idea of best
[sgt/putty] / windows / winhandl.c
index f300962..286f79a 100644 (file)
@@ -250,6 +250,7 @@ struct handle_output {
      * Data only ever read or written by the main thread.
      */
     bufchain queued_data;             /* data still waiting to be written */
+    enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof;
 
     /*
      * Callback function called when the backlog in the bufchain
@@ -262,12 +263,15 @@ static DWORD WINAPI handle_output_threadfunc(void *param)
 {
     struct handle_output *ctx = (struct handle_output *) param;
     OVERLAPPED ovl, *povl;
+    HANDLE oev;
     int writeret;
 
-    if (ctx->flags & HANDLE_FLAG_OVERLAPPED)
+    if (ctx->flags & HANDLE_FLAG_OVERLAPPED) {
        povl = &ovl;
-    else
+       oev = CreateEvent(NULL, TRUE, FALSE, NULL);
+    } else {
        povl = NULL;
+    }
 
     while (1) {
        WaitForSingleObject(ctx->ev_from_main, INFINITE);
@@ -275,8 +279,11 @@ static DWORD WINAPI handle_output_threadfunc(void *param)
            SetEvent(ctx->ev_to_main);
            break;
        }
-       if (povl)
+       if (povl) {
            memset(povl, 0, sizeof(OVERLAPPED));
+           povl->hEvent = oev;
+       }
+
        writeret = WriteFile(ctx->h, ctx->buffer, ctx->len,
                             &ctx->lenwritten, povl);
        if (!writeret)
@@ -297,6 +304,9 @@ static DWORD WINAPI handle_output_threadfunc(void *param)
            break;
     }
 
+    if (povl)
+       CloseHandle(oev);
+
     return 0;
 }
 
@@ -311,6 +321,11 @@ static void handle_try_output(struct handle_output *ctx)
        ctx->len = sendlen;
        SetEvent(ctx->ev_from_main);
        ctx->busy = TRUE;
+    } else if (!ctx->busy && bufchain_size(&ctx->queued_data) == 0 &&
+               ctx->outgoingeof == EOF_PENDING) {
+        CloseHandle(ctx->h);
+        ctx->h = INVALID_HANDLE_VALUE;
+        ctx->outgoingeof = EOF_SENT;
     }
 }
 
@@ -399,6 +414,7 @@ struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata,
     h->u.o.done = FALSE;
     h->u.o.privdata = privdata;
     bufchain_init(&h->u.o.queued_data);
+    h->u.o.outgoingeof = EOF_NO;
     h->u.o.sentdata = sentdata;
     h->u.o.flags = flags;
 
@@ -407,7 +423,7 @@ struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata,
     add234(handles_by_evtomain, h);
 
     CreateThread(NULL, 0, handle_output_threadfunc,
-                &h->u.i, 0, &out_threadid);
+                &h->u.o, 0, &out_threadid);
 
     return h;
 }
@@ -415,11 +431,28 @@ struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata,
 int handle_write(struct handle *h, const void *data, int len)
 {
     assert(h->output);
+    assert(h->u.o.outgoingeof == EOF_NO);
     bufchain_add(&h->u.o.queued_data, data, len);
     handle_try_output(&h->u.o);
     return bufchain_size(&h->u.o.queued_data);
 }
 
+void handle_write_eof(struct handle *h)
+{
+    /*
+     * This function is called when we want to proactively send an
+     * end-of-file notification on the handle. We can only do this by
+     * actually closing the handle - so never call this on a
+     * bidirectional handle if we're still interested in its incoming
+     * direction!
+     */
+    assert(h->output);
+    if (!h->u.o.outgoingeof == EOF_NO) {
+        h->u.o.outgoingeof = EOF_PENDING;
+        handle_try_output(&h->u.o);
+    }
+}
+
 HANDLE *handle_get_events(int *nevents)
 {
     HANDLE *ret;