mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-06-30 19:12:48 -05:00
Created a shiny new abstraction for the socket handling. Has many
advantages: - protocol modules can call sk_write() without having to worry about writes blocking, because blocking writes are handled in the abstraction layer and retried later. - `Lost connection while sending' is a thing of the past. - <winsock.h> is no longer needed in most modules, because "putty.h" doesn't have to declare `SOCKET' variables any more, only the abstracted `Socket' type. - select()-equivalent between multiple sockets will now be handled sensibly, which opens the way for things like SSH port forwarding. [originally from svn r744]
This commit is contained in:
101
plink.c
101
plink.c
@ -11,8 +11,8 @@
|
||||
|
||||
#define PUTTY_DO_GLOBALS /* actually _define_ globals */
|
||||
#include "putty.h"
|
||||
#include "winstuff.h"
|
||||
#include "storage.h"
|
||||
#include "tree234.h"
|
||||
|
||||
void fatalbox (char *p, ...) {
|
||||
va_list ap;
|
||||
@ -121,6 +121,8 @@ void verify_ssh_host_key(char *host, int port, char *keytype,
|
||||
HANDLE outhandle, errhandle;
|
||||
DWORD orig_console_mode;
|
||||
|
||||
WSAEVENT netevent;
|
||||
|
||||
void begin_session(void) {
|
||||
if (!cfg.ldisc_term)
|
||||
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_PROCESSED_INPUT);
|
||||
@ -144,7 +146,7 @@ void from_backend(int is_stderr, char *data, int len) {
|
||||
struct input_data {
|
||||
DWORD len;
|
||||
char buffer[4096];
|
||||
HANDLE event;
|
||||
HANDLE event, eventback;
|
||||
};
|
||||
|
||||
static int get_password(const char *prompt, char *str, int maxlen)
|
||||
@ -196,8 +198,9 @@ static DWORD WINAPI stdin_read_thread(void *param) {
|
||||
inhandle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
while (ReadFile(inhandle, idata->buffer, sizeof(idata->buffer),
|
||||
&idata->len, NULL)) {
|
||||
&idata->len, NULL) && idata->len > 0) {
|
||||
SetEvent(idata->event);
|
||||
WaitForSingleObject(idata->eventback, INFINITE);
|
||||
}
|
||||
|
||||
idata->len = 0;
|
||||
@ -222,19 +225,39 @@ static void usage(void)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *do_select(SOCKET skt, int startup) {
|
||||
int events;
|
||||
if (startup) {
|
||||
events = FD_READ | FD_WRITE | FD_OOB | FD_CLOSE;
|
||||
} else {
|
||||
events = 0;
|
||||
}
|
||||
if (WSAEventSelect (skt, netevent, events) == SOCKET_ERROR) {
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAENETDOWN: return "Network is down";
|
||||
default: return "WSAAsyncSelect(): unknown error";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
WSADATA wsadata;
|
||||
WORD winsock_ver;
|
||||
WSAEVENT netevent, stdinevent;
|
||||
WSAEVENT stdinevent;
|
||||
HANDLE handles[2];
|
||||
SOCKET socket;
|
||||
DWORD threadid;
|
||||
struct input_data idata;
|
||||
int sending;
|
||||
int portnumber = -1;
|
||||
SOCKET *sklist;
|
||||
int skcount, sksize;
|
||||
int connopen;
|
||||
|
||||
ssh_get_password = get_password;
|
||||
|
||||
sklist = NULL; skcount = sksize = 0;
|
||||
|
||||
flags = FLAG_STDERR;
|
||||
/*
|
||||
* Process the command line.
|
||||
@ -429,22 +452,24 @@ int main(int argc, char **argv) {
|
||||
WSACleanup();
|
||||
return 1;
|
||||
}
|
||||
sk_init();
|
||||
|
||||
/*
|
||||
* Start up the connection.
|
||||
*/
|
||||
netevent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
{
|
||||
char *error;
|
||||
char *realhost;
|
||||
|
||||
error = back->init (NULL, cfg.host, cfg.port, &realhost);
|
||||
error = back->init (cfg.host, cfg.port, &realhost);
|
||||
if (error) {
|
||||
fprintf(stderr, "Unable to open connection:\n%s", error);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
connopen = 1;
|
||||
|
||||
netevent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
stdinevent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &orig_console_mode);
|
||||
@ -452,16 +477,11 @@ int main(int argc, char **argv) {
|
||||
outhandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
errhandle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
/*
|
||||
* Now we must send the back end oodles of stuff.
|
||||
*/
|
||||
socket = back->socket();
|
||||
/*
|
||||
* Turn off ECHO and LINE input modes. We don't care if this
|
||||
* call fails, because we know we aren't necessarily running in
|
||||
* a console.
|
||||
*/
|
||||
WSAEventSelect(socket, netevent, FD_READ | FD_CLOSE);
|
||||
handles[0] = netevent;
|
||||
handles[1] = stdinevent;
|
||||
sending = FALSE;
|
||||
@ -486,6 +506,7 @@ int main(int argc, char **argv) {
|
||||
* - so we're back to ReadFile blocking.
|
||||
*/
|
||||
idata.event = stdinevent;
|
||||
idata.eventback = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (!CreateThread(NULL, 0, stdin_read_thread,
|
||||
&idata, 0, &threadid)) {
|
||||
fprintf(stderr, "Unable to create second thread\n");
|
||||
@ -497,22 +518,62 @@ int main(int argc, char **argv) {
|
||||
n = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
|
||||
if (n == 0) {
|
||||
WSANETWORKEVENTS things;
|
||||
if (!WSAEnumNetworkEvents(socket, netevent, &things)) {
|
||||
if (things.lNetworkEvents & FD_READ)
|
||||
back->msg(0, FD_READ);
|
||||
if (things.lNetworkEvents & FD_CLOSE) {
|
||||
back->msg(0, FD_CLOSE);
|
||||
break;
|
||||
}
|
||||
enum234 e;
|
||||
SOCKET socket;
|
||||
extern SOCKET first_socket(enum234 *), next_socket(enum234 *);
|
||||
extern int select_result(WPARAM, LPARAM);
|
||||
int i;
|
||||
|
||||
/*
|
||||
* We must not call select_result() for any socket
|
||||
* until we have finished enumerating within the tree.
|
||||
* This is because select_result() may close the socket
|
||||
* and modify the tree.
|
||||
*/
|
||||
/* Count the active sockets. */
|
||||
i = 0;
|
||||
for (socket = first_socket(&e); socket != INVALID_SOCKET;
|
||||
socket = next_socket(&e))
|
||||
i++;
|
||||
|
||||
/* Expand the buffer if necessary. */
|
||||
if (i > sksize) {
|
||||
sksize = i+16;
|
||||
sklist = srealloc(sklist, sksize * sizeof(*sklist));
|
||||
}
|
||||
|
||||
/* Retrieve the sockets into sklist. */
|
||||
skcount = 0;
|
||||
for (socket = first_socket(&e); socket != INVALID_SOCKET;
|
||||
socket = next_socket(&e)) {
|
||||
sklist[skcount++] = socket;
|
||||
}
|
||||
|
||||
/* Now we're done enumerating; go through the list. */
|
||||
for (i = 0; i < skcount; i++) {
|
||||
WPARAM wp;
|
||||
socket = sklist[i];
|
||||
wp = (WPARAM)socket;
|
||||
if (!WSAEnumNetworkEvents(socket, netevent, &things)) {
|
||||
if (things.lNetworkEvents & FD_READ)
|
||||
connopen &= select_result(wp, (LPARAM)FD_READ);
|
||||
if (things.lNetworkEvents & FD_CLOSE)
|
||||
connopen &= select_result(wp, (LPARAM)FD_CLOSE);
|
||||
if (things.lNetworkEvents & FD_OOB)
|
||||
connopen &= select_result(wp, (LPARAM)FD_OOB);
|
||||
if (things.lNetworkEvents & FD_WRITE)
|
||||
connopen &= select_result(wp, (LPARAM)FD_WRITE);
|
||||
}
|
||||
}
|
||||
} else if (n == 1) {
|
||||
if (idata.len > 0) {
|
||||
back->send(idata.buffer, idata.len);
|
||||
} else {
|
||||
back->special(TS_EOF);
|
||||
}
|
||||
SetEvent(idata.eventback);
|
||||
}
|
||||
if (back->socket() == INVALID_SOCKET)
|
||||
if (!connopen || back->socket() == NULL)
|
||||
break; /* we closed the connection */
|
||||
}
|
||||
WSACleanup();
|
||||
|
Reference in New Issue
Block a user