mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-07-02 03:52:49 -05:00
Revamp of EOF handling in all network connections, pipes and other
data channels. Should comprehensively fix 'half-closed', in principle, though it's a big and complicated change and so there's a good chance I've made at least one mistake somewhere. All connections should now be rigorous about propagating end-of-file (or end-of-data-stream, or socket shutdown, or whatever) independently in both directions, except in frontends with no mechanism for sending explicit EOF (e.g. interactive terminal windows) or backends which are basically always used for interactive sessions so it's unlikely that an application would be depending on independent EOF (telnet, rlogin). EOF should now never accidentally be sent while there's still buffered data to go out before it. (May help fix 'portfwd-corrupt', and also I noticed recently that the ssh main session channel can accidentally have MSG_EOF sent before the output bufchain is clear, leading to embarrassment when it subsequently does send the output). [originally from svn r9279]
This commit is contained in:
@ -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
|
||||
@ -320,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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -408,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;
|
||||
|
||||
@ -424,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;
|
||||
|
Reference in New Issue
Block a user