1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-04-18 03:28:07 -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; last_movement = now;
} }
} }
net_pending_errors();
return 0; return 0;
case WM_CREATE: case WM_CREATE:
break; break;
@ -1614,6 +1615,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
InvalidateRect(hwnd, NULL, TRUE); InvalidateRect(hwnd, NULL, TRUE);
reset_window(init_lvl); reset_window(init_lvl);
net_pending_errors();
} }
break; break;
case IDM_COPYALL: case IDM_COPYALL:
@ -1627,42 +1629,55 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
break; break;
case IDM_TEL_AYT: case IDM_TEL_AYT:
back->special(TS_AYT); back->special(TS_AYT);
net_pending_errors();
break; break;
case IDM_TEL_BRK: case IDM_TEL_BRK:
back->special(TS_BRK); back->special(TS_BRK);
net_pending_errors();
break; break;
case IDM_TEL_SYNCH: case IDM_TEL_SYNCH:
back->special(TS_SYNCH); back->special(TS_SYNCH);
net_pending_errors();
break; break;
case IDM_TEL_EC: case IDM_TEL_EC:
back->special(TS_EC); back->special(TS_EC);
net_pending_errors();
break; break;
case IDM_TEL_EL: case IDM_TEL_EL:
back->special(TS_EL); back->special(TS_EL);
net_pending_errors();
break; break;
case IDM_TEL_GA: case IDM_TEL_GA:
back->special(TS_GA); back->special(TS_GA);
net_pending_errors();
break; break;
case IDM_TEL_NOP: case IDM_TEL_NOP:
back->special(TS_NOP); back->special(TS_NOP);
net_pending_errors();
break; break;
case IDM_TEL_ABORT: case IDM_TEL_ABORT:
back->special(TS_ABORT); back->special(TS_ABORT);
net_pending_errors();
break; break;
case IDM_TEL_AO: case IDM_TEL_AO:
back->special(TS_AO); back->special(TS_AO);
net_pending_errors();
break; break;
case IDM_TEL_IP: case IDM_TEL_IP:
back->special(TS_IP); back->special(TS_IP);
net_pending_errors();
break; break;
case IDM_TEL_SUSP: case IDM_TEL_SUSP:
back->special(TS_SUSP); back->special(TS_SUSP);
net_pending_errors();
break; break;
case IDM_TEL_EOR: case IDM_TEL_EOR:
back->special(TS_EOR); back->special(TS_EOR);
net_pending_errors();
break; break;
case IDM_TEL_EOF: case IDM_TEL_EOF:
back->special(TS_EOF); back->special(TS_EOF);
net_pending_errors();
break; break;
case IDM_ABOUT: case IDM_ABOUT:
showabout(hwnd); showabout(hwnd);
@ -2188,6 +2203,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
} }
} }
} }
net_pending_errors();
return 0; return 0;
case WM_INPUTLANGCHANGE: case WM_INPUTLANGCHANGE:
{ {

View File

@ -72,6 +72,7 @@ struct Socket_tag {
char oobdata[1]; char oobdata[1];
int sending_oob; int sending_oob;
int oobinline; 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 = 1;
ret->frozen_readable = 0; ret->frozen_readable = 0;
ret->localhost_only = 0; /* unused, but best init anyway */ ret->localhost_only = 0; /* unused, but best init anyway */
ret->pending_error = 0;
ret->s = (SOCKET)sock; ret->s = (SOCKET)sock;
@ -472,6 +474,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
ret->frozen = 0; ret->frozen = 0;
ret->frozen_readable = 0; ret->frozen_readable = 0;
ret->localhost_only = 0; /* unused, but best init anyway */ ret->localhost_only = 0; /* unused, but best init anyway */
ret->pending_error = 0;
/* /*
* Open socket. * Open socket.
@ -640,6 +643,7 @@ Socket sk_newlistener(int port, Plug plug, int local_host_only)
ret->frozen = 0; ret->frozen = 0;
ret->frozen_readable = 0; ret->frozen_readable = 0;
ret->localhost_only = local_host_only; ret->localhost_only = local_host_only;
ret->pending_error = 0;
/* /*
* Open socket. * Open socket.
@ -768,30 +772,17 @@ void try_send(Actual_Socket s)
} else if (nsent == 0 || } else if (nsent == 0 ||
err == WSAECONNABORTED || err == WSAECONNRESET) { err == WSAECONNABORTED || err == WSAECONNRESET) {
/* /*
* ASSUMPTION: * If send() returns CONNABORTED or CONNRESET, we
* * unfortunately can't just call plug_closing(),
* I'm assuming here that if a TCP connection is * because it's quite likely that we're currently
* reset or aborted once established, we will be * _in_ a call from the code we'd be calling back
* notified by a select event rather than a * to, so we'd have to make half the SSH code
* CONNABORTED or CONNRESET from send(). In other * reentrant. Instead we flag a pending error on
* words, I'm assuming CONNABORTED and CONNRESET * the socket, to be dealt with (by calling
* don't come back from a _nonblocking_ send(), * plug_closing()) at some suitable future moment.
* 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.
*/ */
fatalbox("SERIOUS NETWORK INTERNAL ERROR: %s\n" s->pending_error = err;
"Please report this immediately to " return;
"<putty@projects.tartarus.org>.",
winsock_error_string(err));
} else { } else {
fatalbox(winsock_error_string(err)); fatalbox(winsock_error_string(err));
} }
@ -993,6 +984,44 @@ int select_result(WPARAM wParam, LPARAM lParam)
return 1; 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 * Each socket abstraction contains a `void *' private field in
* which the client can keep state. * which the client can keep state.