1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-04-10 15:48:06 -05:00

Fix the `SERIOUS NETWORK INTERNAL ERROR' oversight in winnet.c. See

the comment in try_send() for details of the problem.

[originally from svn r1335]
This commit is contained in:
Simon Tatham 2001-10-28 09:57:47 +00:00
parent 9bbe53d700
commit 555ded7740
2 changed files with 68 additions and 23 deletions

View File

@ -1410,6 +1410,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
last_movement = now;
}
}
net_pending_errors();
return 0;
case WM_CREATE:
break;
@ -1614,6 +1615,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
InvalidateRect(hwnd, NULL, TRUE);
reset_window(init_lvl);
net_pending_errors();
}
break;
case IDM_COPYALL:
@ -1627,42 +1629,55 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
break;
case IDM_TEL_AYT:
back->special(TS_AYT);
net_pending_errors();
break;
case IDM_TEL_BRK:
back->special(TS_BRK);
net_pending_errors();
break;
case IDM_TEL_SYNCH:
back->special(TS_SYNCH);
net_pending_errors();
break;
case IDM_TEL_EC:
back->special(TS_EC);
net_pending_errors();
break;
case IDM_TEL_EL:
back->special(TS_EL);
net_pending_errors();
break;
case IDM_TEL_GA:
back->special(TS_GA);
net_pending_errors();
break;
case IDM_TEL_NOP:
back->special(TS_NOP);
net_pending_errors();
break;
case IDM_TEL_ABORT:
back->special(TS_ABORT);
net_pending_errors();
break;
case IDM_TEL_AO:
back->special(TS_AO);
net_pending_errors();
break;
case IDM_TEL_IP:
back->special(TS_IP);
net_pending_errors();
break;
case IDM_TEL_SUSP:
back->special(TS_SUSP);
net_pending_errors();
break;
case IDM_TEL_EOR:
back->special(TS_EOR);
net_pending_errors();
break;
case IDM_TEL_EOF:
back->special(TS_EOF);
net_pending_errors();
break;
case IDM_ABOUT:
showabout(hwnd);
@ -2188,6 +2203,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
}
}
}
net_pending_errors();
return 0;
case WM_INPUTLANGCHANGE:
{

View File

@ -72,6 +72,7 @@ struct Socket_tag {
char oobdata[1];
int sending_oob;
int oobinline;
int pending_error; /* in case send() returns error */
};
/*
@ -412,6 +413,7 @@ Socket sk_register(void *sock, Plug plug)
ret->frozen = 1;
ret->frozen_readable = 0;
ret->localhost_only = 0; /* unused, but best init anyway */
ret->pending_error = 0;
ret->s = (SOCKET)sock;
@ -472,6 +474,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
ret->frozen = 0;
ret->frozen_readable = 0;
ret->localhost_only = 0; /* unused, but best init anyway */
ret->pending_error = 0;
/*
* Open socket.
@ -640,6 +643,7 @@ Socket sk_newlistener(int port, Plug plug, int local_host_only)
ret->frozen = 0;
ret->frozen_readable = 0;
ret->localhost_only = local_host_only;
ret->pending_error = 0;
/*
* Open socket.
@ -768,30 +772,17 @@ void try_send(Actual_Socket s)
} else if (nsent == 0 ||
err == WSAECONNABORTED || err == WSAECONNRESET) {
/*
* ASSUMPTION:
*
* I'm assuming here that if a TCP connection is
* reset or aborted once established, we will be
* notified by a select event rather than a
* CONNABORTED or CONNRESET from send(). In other
* words, I'm assuming CONNABORTED and CONNRESET
* don't come back from a _nonblocking_ send(),
* because the local side doesn't know they've
* happened until it waits for a response to its
* TCP segment - so the error will arrive
* asynchronously.
*
* If I'm wrong, this will be a really nasty case,
* because we can't necessarily call plug_closing()
* without having to make half the SSH code
* reentrant; so instead we'll have to schedule a
* call to plug_closing() for some suitable future
* time.
* If send() returns CONNABORTED or CONNRESET, we
* unfortunately can't just call plug_closing(),
* because it's quite likely that we're currently
* _in_ a call from the code we'd be calling back
* to, so we'd have to make half the SSH code
* reentrant. Instead we flag a pending error on
* the socket, to be dealt with (by calling
* plug_closing()) at some suitable future moment.
*/
fatalbox("SERIOUS NETWORK INTERNAL ERROR: %s\n"
"Please report this immediately to "
"<putty@projects.tartarus.org>.",
winsock_error_string(err));
s->pending_error = err;
return;
} else {
fatalbox(winsock_error_string(err));
}
@ -993,6 +984,44 @@ int select_result(WPARAM wParam, LPARAM lParam)
return 1;
}
/*
* Deal with socket errors detected in try_send().
*/
void net_pending_errors(void)
{
int i;
Actual_Socket s;
/*
* This might be a fiddly business, because it's just possible
* that handling a pending error on one socket might cause
* others to be closed. (I can't think of any reason this might
* happen in current SSH implementation, but to maintain
* generality of this network layer I'll assume the worst.)
*
* So what we'll do is search the socket list for _one_ socket
* with a pending error, and then handle it, and then search
* the list again _from the beginning_. Repeat until we make a
* pass with no socket errors present. That way we are
* protected against the socket list changing under our feet.
*/
do {
for (i = 0; (s = index234(sktree, i)) != NULL; i++) {
if (s->pending_error) {
/*
* An error has occurred on this socket. Pass it to the
* plug.
*/
plug_closing(s->plug,
winsock_error_string(s->pending_error),
s->pending_error, 0);
break;
}
}
} while (s);
}
/*
* Each socket abstraction contains a `void *' private field in
* which the client can keep state.