X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/21ae394fa51be066449b33860ec7c1fe43c9c784..c9017afc2ece6fb3f69ef866845d7dc7ee73bbf2:/windows/winhandl.c diff --git a/windows/winhandl.c b/windows/winhandl.c index f300962c..286f79a6 100644 --- a/windows/winhandl.c +++ b/windows/winhandl.c @@ -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;