From 8df7a775f6f8b0f81f84eafe28cd0bb8d4c6d1f4 Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 23 Oct 2000 10:32:37 +0000 Subject: [PATCH] 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. - 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. git-svn-id: svn://svn.tartarus.org/sgt/putty@744 cda61777-01e9-0310-a592-d414129be87e --- Makefile | 49 ++++---- be_all.c | 7 -- be_none.c | 7 -- be_nossh.c | 7 -- ldisc.c | 7 -- misc.c | 7 -- noise.c | 7 -- plink.c | 101 ++++++++++++--- putty.h | 7 +- raw.c | 184 ++++------------------------ scp.c | 38 +++--- settings.c | 7 -- sizetip.c | 7 -- ssh.c | 405 ++++++++++++++++++++++++------------------------------------- telnet.c | 245 ++++++++----------------------------- terminal.c | 20 ++- windlg.c | 7 -- window.c | 47 ++++--- winstore.c | 7 -- xlat.c | 7 -- 20 files changed, 407 insertions(+), 766 deletions(-) diff --git a/Makefile b/Makefile index 4e20f611..27f72bb8 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ RES=res GOBJS1 = window.$(OBJ) windlg.$(OBJ) winctrls.$(OBJ) terminal.$(OBJ) GOBJS2 = xlat.$(OBJ) sizetip.$(OBJ) ##-- objects putty puttytel plink -LOBJS1 = telnet.$(OBJ) raw.$(OBJ) ldisc.$(OBJ) +LOBJS1 = telnet.$(OBJ) raw.$(OBJ) ldisc.$(OBJ) winnet.$(OBJ) ##-- objects putty plink POBJS = be_all.$(OBJ) ##-- objects puttytel @@ -62,13 +62,14 @@ TOBJS = be_nossh.$(OBJ) ##-- objects plink PLOBJS = plink.$(OBJ) ##-- objects pscp -SOBJS = scp.$(OBJ) be_none.$(OBJ) +SOBJS = scp.$(OBJ) winnet.$(OBJ) be_none.$(OBJ) ##-- objects putty puttytel pscp plink MOBJS = misc.$(OBJ) version.$(OBJ) winstore.$(OBJ) settings.$(OBJ) +MOBJ2 = tree234.$(OBJ) ##-- objects putty pscp plink OBJS1 = sshcrc.$(OBJ) sshdes.$(OBJ) sshmd5.$(OBJ) sshrsa.$(OBJ) sshrand.$(OBJ) OBJS2 = sshsha.$(OBJ) sshblowf.$(OBJ) noise.$(OBJ) sshdh.$(OBJ) sshdss.$(OBJ) -OBJS3 = sshbn.$(OBJ) sshpubk.$(OBJ) ssh.$(OBJ) pageantc.$(OBJ) tree234.$(OBJ) +OBJS3 = sshbn.$(OBJ) sshpubk.$(OBJ) ssh.$(OBJ) pageantc.$(OBJ) ##-- objects pageant PAGE1 = pageant.$(OBJ) sshrsa.$(OBJ) sshpubk.$(OBJ) sshdes.$(OBJ) sshbn.$(OBJ) PAGE2 = sshmd5.$(OBJ) version.$(OBJ) tree234.$(OBJ) @@ -107,10 +108,10 @@ SOCK2 = ws2_32.lib all: putty.exe puttytel.exe pscp.exe plink.exe pageant.exe puttygen.exe -putty.exe: $(GOBJS1) $(GOBJS2) $(LOBJS1) $(POBJS) $(MOBJS) $(OBJS1) $(OBJS2) $(OBJS3) $(PRESRC) putty.rsp +putty.exe: $(GOBJS1) $(GOBJS2) $(LOBJS1) $(POBJS) $(MOBJS) $(MOBJ2) $(OBJS1) $(OBJS2) $(OBJS3) $(PRESRC) putty.rsp link $(LFLAGS) -out:putty.exe @putty.rsp -puttytel.exe: $(GOBJS1) $(GOBJS2) $(LOBJS1) $(TOBJS) $(MOBJS) $(PRESRC) puttytel.rsp +puttytel.exe: $(GOBJS1) $(GOBJS2) $(LOBJS1) $(TOBJS) $(MOBJS) $(MOBJ2) $(PRESRC) puttytel.rsp link $(LFLAGS) -out:puttytel.exe @puttytel.rsp pageant.exe: $(PAGE1) $(PAGE2) $(PAGERC) pageant.rsp @@ -119,10 +120,10 @@ pageant.exe: $(PAGE1) $(PAGE2) $(PAGERC) pageant.rsp puttygen.exe: $(GEN1) $(GEN2) $(GEN3) $(GEN4) $(GENRC) puttygen.rsp link $(LFLAGS) -out:puttygen.exe @puttygen.rsp -pscp.exe: $(SOBJS) $(MOBJS) $(OBJS1) $(OBJS2) $(OBJS3) $(SRESRC) pscp.rsp +pscp.exe: $(SOBJS) $(MOBJS) $(MOBJ2) $(OBJS1) $(OBJS2) $(OBJS3) $(SRESRC) pscp.rsp link $(LFLAGS) -out:pscp.exe @pscp.rsp -plink.exe: $(LOBJS1) $(POBJS) $(PLOBJS) $(MOBJS) $(OBJS1) $(OBJS2) $(OBJS3) $(LRESRC) plink.rsp +plink.exe: $(LOBJS1) $(POBJS) $(PLOBJS) $(MOBJS) $(MOBJ2) $(OBJS1) $(OBJS2) $(OBJS3) $(LRESRC) plink.rsp link $(LFLAGS) -out:plink.exe @plink.rsp putty.rsp: makefile @@ -132,6 +133,7 @@ putty.rsp: makefile echo $(LOBJS1) >> putty.rsp echo $(POBJS) >> putty.rsp echo $(MOBJS) >> putty.rsp + echo $(MOBJ2) >> putty.rsp echo $(OBJS1) >> putty.rsp echo $(OBJS2) >> putty.rsp echo $(OBJS3) >> putty.rsp @@ -147,6 +149,7 @@ puttytel.rsp: makefile echo $(LOBJS1) >> puttytel.rsp echo $(TOBJS) >> puttytel.rsp echo $(MOBJS) >> puttytel.rsp + echo $(MOBJ2) >> puttytel.rsp echo $(PRESRC) >> puttytel.rsp echo $(LIBS1) >> puttytel.rsp echo $(LIBS2) >> puttytel.rsp @@ -176,6 +179,7 @@ pscp.rsp: makefile echo /nologo /subsystem:console > pscp.rsp echo $(SOBJS) >> pscp.rsp echo $(MOBJS) >> pscp.rsp + echo $(MOBJ2) >> pscp.rsp echo $(OBJS1) >> pscp.rsp echo $(OBJS2) >> pscp.rsp echo $(OBJS3) >> pscp.rsp @@ -190,6 +194,7 @@ plink.rsp: makefile echo $(POBJS) >> plink.rsp echo $(PLOBJS) >> plink.rsp echo $(MOBJS) >> plink.rsp + echo $(MOBJ2) >> plink.rsp echo $(OBJS1) >> plink.rsp echo $(OBJS2) >> plink.rsp echo $(OBJS3) >> plink.rsp @@ -199,20 +204,20 @@ plink.rsp: makefile echo $(SOCK2) >> plink.rsp ##-- dependencies -window.$(OBJ): window.c putty.h win_res.h storage.h winstuff.h -windlg.$(OBJ): windlg.c putty.h ssh.h win_res.h winstuff.h +window.$(OBJ): window.c putty.h network.h win_res.h storage.h winstuff.h +windlg.$(OBJ): windlg.c putty.h network.h ssh.h win_res.h winstuff.h winctrls.$(OBJ): winctrls.c winstuff.h winstuff.h -settings.$(OBJ): settings.c putty.h storage.h -winstore.$(OBJ): winstore.c putty.h storage.h -terminal.$(OBJ): terminal.c putty.h -sizetip.$(OBJ): sizetip.c putty.h winstuff.h -telnet.$(OBJ): telnet.c putty.h -raw.$(OBJ): raw.c putty.h -xlat.$(OBJ): xlat.c putty.h -ldisc.$(OBJ): ldisc.c putty.h -misc.$(OBJ): misc.c putty.h -noise.$(OBJ): noise.c putty.h ssh.h storage.h -ssh.$(OBJ): ssh.c ssh.h putty.h tree234.h +settings.$(OBJ): settings.c putty.h network.h storage.h +winstore.$(OBJ): winstore.c putty.h network.h storage.h +terminal.$(OBJ): terminal.c putty.h network.h +sizetip.$(OBJ): sizetip.c putty.h network.h winstuff.h +telnet.$(OBJ): telnet.c putty.h network.h +raw.$(OBJ): raw.c putty.h network.h +xlat.$(OBJ): xlat.c putty.h network.h +ldisc.$(OBJ): ldisc.c putty.h network.h +misc.$(OBJ): misc.c putty.h network.h +noise.$(OBJ): noise.c putty.h network.h ssh.h storage.h +ssh.$(OBJ): ssh.c ssh.h putty.h network.h tree234.h sshcrc.$(OBJ): sshcrc.c ssh.h sshdes.$(OBJ): sshdes.c ssh.h sshmd5.$(OBJ): sshmd5.c ssh.h @@ -224,12 +229,12 @@ sshdh.$(OBJ): sshdh.c ssh.h sshdss.$(OBJ): sshdss.c ssh.h sshbn.$(OBJ): sshbn.c ssh.h sshpubk.$(OBJ): sshpubk.c ssh.h -scp.$(OBJ): scp.c putty.h winstuff.h +scp.$(OBJ): scp.c putty.h network.h winstuff.h version.$(OBJ): version.c be_all.$(OBJ): be_all.c be_nossh.$(OBJ): be_nossh.c be_none.$(OBJ): be_none.c -plink.$(OBJ): plink.c putty.h winstuff.h +plink.$(OBJ): plink.c putty.h network.h winstuff.h pageant.$(OBJ): pageant.c ssh.h tree234.h tree234.$(OBJ): tree234.c tree234.h ##-- diff --git a/be_all.c b/be_all.c index ae58771e..69e44b76 100644 --- a/be_all.c +++ b/be_all.c @@ -4,13 +4,6 @@ */ #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include #include "putty.h" diff --git a/be_none.c b/be_none.c index 8151b3d7..d112143e 100644 --- a/be_none.c +++ b/be_none.c @@ -5,13 +5,6 @@ */ #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include #include "putty.h" diff --git a/be_nossh.c b/be_nossh.c index 5dac276f..fdd98288 100644 --- a/be_nossh.c +++ b/be_nossh.c @@ -4,13 +4,6 @@ */ #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include #include "putty.h" diff --git a/ldisc.c b/ldisc.c index 10576d29..80659cca 100644 --- a/ldisc.c +++ b/ldisc.c @@ -1,11 +1,4 @@ #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include #include diff --git a/misc.c b/misc.c index e06ced64..6bb09c53 100644 --- a/misc.c +++ b/misc.c @@ -1,11 +1,4 @@ #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include #include #include "putty.h" diff --git a/noise.c b/noise.c index 1d764d5f..af75f9d8 100644 --- a/noise.c +++ b/noise.c @@ -4,13 +4,6 @@ */ #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include #include "putty.h" diff --git a/plink.c b/plink.c index 26a17292..f5f6c8a0 100644 --- a/plink.c +++ b/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); @@ -453,15 +478,10 @@ int main(int argc, char **argv) { 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(); diff --git a/putty.h b/putty.h index 7f14f3d9..ae936b01 100644 --- a/putty.h +++ b/putty.h @@ -1,6 +1,8 @@ #ifndef PUTTY_PUTTY_H #define PUTTY_PUTTY_H +#include "network.h" + #define PUTTY_REG_POS "Software\\SimonTatham\\PuTTY" #define PUTTY_REG_PARENT "Software\\SimonTatham" #define PUTTY_REG_PARENT_CHILD "PuTTY" @@ -104,12 +106,11 @@ typedef enum { } VT_Mode; typedef struct { - char *(*init) (HWND hwnd, char *host, int port, char **realhost); - int (*msg) (WPARAM wParam, LPARAM lParam); + char *(*init) (char *host, int port, char **realhost); void (*send) (char *buf, int len); void (*size) (void); void (*special) (Telnet_Special code); - SOCKET (*socket) (void); + Socket (*socket) (void); int (*sendok) (void); int default_port; } Backend; diff --git a/raw.c b/raw.c index 3f82d7ad..833f8432 100644 --- a/raw.c +++ b/raw.c @@ -1,13 +1,6 @@ #include #include #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include "putty.h" @@ -18,7 +11,7 @@ #define TRUE 1 #endif -static SOCKET s = INVALID_SOCKET; +static Socket s = NULL; static void raw_size(void); @@ -27,67 +20,38 @@ static char *sb_buf = NULL; static int sb_size = 0; #define SB_DELTA 1024 -static void try_write (void) { - while (outbuf_head != outbuf_reap) { - int end = (outbuf_reap < outbuf_head ? outbuf_head : OUTBUF_SIZE); - int len = end - outbuf_reap; - int ret; - - ret = send (s, outbuf+outbuf_reap, len, 0); - if (ret > 0) - outbuf_reap = (outbuf_reap + ret) & OUTBUF_MASK; - if (ret < len) - return; - } +static void c_write (char *buf, int len) { + from_backend(0, buf, len); } -static void s_write (void *buf, int len) { - unsigned char *p = buf; - while (len--) { - int new_head = (outbuf_head + 1) & OUTBUF_MASK; - if (new_head != outbuf_reap) { - outbuf[outbuf_head] = *p++; - outbuf_head = new_head; - } +static int raw_receive (Socket s, int urgent, char *data, int len) { + if (!len) { + /* Connection has closed. */ + sk_close(s); + s = NULL; + return 0; } - try_write(); -} - -static void c_write (char *buf, int len) { - from_backend(0, buf, len); + c_write(data, len); + return 1; } /* - * Called to set up the raw connection. Will arrange for - * WM_NETEVENT messages to be passed to the specified window, whose - * window procedure should then call raw_msg(). - * + * Called to set up the raw connection. + * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. */ -static char *raw_init (HWND hwnd, char *host, int port, char **realhost) { - SOCKADDR_IN addr; - struct hostent *h; - unsigned long a; +static char *raw_init (char *host, int port, char **realhost) { + SockAddr addr; + char *err; /* * Try to find host. */ - if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) { - if ( (h = gethostbyname(host)) == NULL) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - case WSAHOST_NOT_FOUND: case WSANO_DATA: - return "Host does not exist"; - case WSATRY_AGAIN: return "Host not found"; - default: return "gethostbyname: unknown error"; - } - memcpy (&a, h->h_addr, sizeof(a)); - *realhost = h->h_name; - } else - *realhost = host; - a = ntohl(a); + addr = sk_namelookup(host, realhost); + if ( (err = sk_addr_error(addr)) ) + return err; if (port < 0) port = 23; /* default telnet port */ @@ -95,46 +59,11 @@ static char *raw_init (HWND hwnd, char *host, int port, char **realhost) { /* * Open socket. */ - s = socket(AF_INET, SOCK_STREAM, 0); - if (s == INVALID_SOCKET) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - case WSAEAFNOSUPPORT: return "TCP/IP support not present"; - default: return "socket(): unknown error"; - } + s = sk_new(addr, port, raw_receive); + if ( (err = sk_socket_error(s)) ) + return err; - /* - * Bind to local address. - */ - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - addr.sin_port = htons(0); - if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - default: return "bind(): unknown error"; - } - - /* - * Connect to remote address. - */ - addr.sin_addr.s_addr = htonl(a); - addr.sin_port = htons((short)port); - if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - case WSAECONNREFUSED: return "Connection refused"; - case WSAENETUNREACH: return "Network is unreachable"; - case WSAEHOSTUNREACH: return "No route to host"; - default: return "connect(): unknown error"; - } - - if (hwnd && WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ | - FD_WRITE | FD_OOB | FD_CLOSE) == SOCKET_ERROR) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - default: return "WSAAsyncSelect(): unknown error"; - } + sk_addr_free(addr); /* * We have no pre-session phase. @@ -145,74 +74,14 @@ static char *raw_init (HWND hwnd, char *host, int port, char **realhost) { } /* - * Process a WM_NETEVENT message. Will return 0 if the connection - * has closed, or <0 for a socket error. - */ -static int raw_msg (WPARAM wParam, LPARAM lParam) { - int ret; - char buf[256]; - - /* - * Because reading less than the whole of the available pending - * data can generate an FD_READ event, we need to allow for the - * possibility that FD_READ may arrive with FD_CLOSE already in - * the queue; so it's possible that we can get here even with s - * invalid. If so, we return 1 and don't worry about it. - */ - if (s == INVALID_SOCKET) { - closesocket(s); - s = INVALID_SOCKET; - return 1; - } - - if (WSAGETSELECTERROR(lParam) != 0) - return -WSAGETSELECTERROR(lParam); - - switch (WSAGETSELECTEVENT(lParam)) { - case FD_READ: - case FD_CLOSE: - ret = recv(s, buf, sizeof(buf), 0); - if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK) - return 1; - if (ret < 0) { /* any _other_ error */ - closesocket(s); - s = INVALID_SOCKET; - return -10000-WSAGetLastError(); - } - if (ret == 0) { - s = INVALID_SOCKET; - return 0; - } - c_write( buf, ret ); - return 1; - case FD_OOB: - do { - ret = recv(s, buf, sizeof(buf), 0); - c_write( buf, ret ); - } while (ret > 0); - do { - ret = recv(s, buf, 1, MSG_OOB); - } while (ret > 0); - if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK) - return -30000-WSAGetLastError(); - return 1; - case FD_WRITE: - if (outbuf_head != outbuf_reap) - try_write(); - return 1; - } - return 1; /* shouldn't happen, but WTF */ -} - -/* * Called to send data down the raw connection. */ static void raw_send (char *buf, int len) { - if (s == INVALID_SOCKET) + if (s == NULL) return; - s_write( buf, len ); + sk_write(s, buf, len); } /* @@ -231,13 +100,12 @@ static void raw_special (Telnet_Special code) { return; } -static SOCKET raw_socket(void) { return s; } +static Socket raw_socket(void) { return s; } static int raw_sendok(void) { return 1; } Backend raw_backend = { raw_init, - raw_msg, raw_send, raw_size, raw_special, diff --git a/scp.c b/scp.c index 401d444c..81f925bb 100644 --- a/scp.c +++ b/scp.c @@ -242,6 +242,19 @@ void connection_fatal(char *fmt, ...) } /* + * Be told what socket we're supposed to be using. + */ +static SOCKET scp_ssh_socket; +char *do_select(SOCKET skt, int startup) { + if (startup) + scp_ssh_socket = skt; + else + scp_ssh_socket = INVALID_SOCKET; + return NULL; +} +extern int select_result(WPARAM, LPARAM); + +/* * Receive a block of data from the SSH link. Block until all data * is available. * @@ -249,6 +262,7 @@ void connection_fatal(char *fmt, ...) * own trap in from_backend() to catch the data that comes back. We * do this until we have enough data. */ + static unsigned char *outptr; /* where to put the data */ static unsigned outlen; /* how much data required */ static unsigned char *pending = NULL; /* any spare data */ @@ -295,8 +309,6 @@ void from_backend(int is_stderr, char *data, int datalen) { } } static int ssh_scp_recv(unsigned char *buf, int len) { - SOCKET s; - outptr = buf; outlen = len; @@ -324,16 +336,12 @@ static int ssh_scp_recv(unsigned char *buf, int len) { while (outlen > 0) { fd_set readfds; - s = back->socket(); - if (s == INVALID_SOCKET) { - connection_open = FALSE; - return 0; - } + FD_ZERO(&readfds); - FD_SET(s, &readfds); + FD_SET(scp_ssh_socket, &readfds); if (select(1, &readfds, NULL, NULL, NULL) < 0) return 0; /* doom */ - back->msg(0, FD_READ); + select_result((WPARAM)scp_ssh_socket, (LPARAM)FD_READ); } return len; @@ -343,18 +351,15 @@ static int ssh_scp_recv(unsigned char *buf, int len) { * Loop through the ssh connection and authentication process. */ static void ssh_scp_init(void) { - SOCKET s; - - s = back->socket(); - if (s == INVALID_SOCKET) + if (scp_ssh_socket == INVALID_SOCKET) return; while (!back->sendok()) { fd_set readfds; FD_ZERO(&readfds); - FD_SET(s, &readfds); + FD_SET(scp_ssh_socket, &readfds); if (select(1, &readfds, NULL, NULL, NULL) < 0) return; /* doom */ - back->msg(0, FD_READ); + select_result((WPARAM)scp_ssh_socket, (LPARAM)FD_READ); } } @@ -464,7 +469,7 @@ static void do_cmd(char *host, char *user, char *cmd) back = &ssh_backend; - err = back->init(NULL, cfg.host, cfg.port, &realhost); + err = back->init(cfg.host, cfg.port, &realhost); if (err != NULL) bump("ssh_init: %s", err); ssh_scp_init(); @@ -1178,6 +1183,7 @@ int main(int argc, char *argv[]) flags = FLAG_STDERR; ssh_get_password = &get_password; init_winsock(); + sk_init(); for (i = 1; i < argc; i++) { if (argv[i][0] != '-') diff --git a/settings.c b/settings.c index a5414419..e762abaf 100644 --- a/settings.c +++ b/settings.c @@ -3,13 +3,6 @@ */ #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include #include "putty.h" #include "storage.h" diff --git a/sizetip.c b/sizetip.c index 439d88ca..10bdee52 100644 --- a/sizetip.c +++ b/sizetip.c @@ -1,11 +1,4 @@ #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include #include #include diff --git a/ssh.c b/ssh.c index c065f2f8..744c86d3 100644 --- a/ssh.c +++ b/ssh.c @@ -1,14 +1,8 @@ +#include #include #include #include #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include "putty.h" #include "tree234.h" @@ -25,8 +19,8 @@ if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) \ fprintf(stderr, "%s\n", s); } -#define bombout(msg) ( ssh_state = SSH_STATE_CLOSED, closesocket(s), \ - s = INVALID_SOCKET, connection_fatal msg ) +#define bombout(msg) ( ssh_state = SSH_STATE_CLOSED, sk_close(s), \ + s = NULL, connection_fatal msg ) #define SSH1_MSG_DISCONNECT 1 /* 0x1 */ #define SSH1_SMSG_PUBLIC_KEY 2 /* 0x2 */ @@ -217,7 +211,7 @@ struct Packet { static SHA_State exhash; -static SOCKET s = INVALID_SOCKET; +static Socket s = NULL; static unsigned char session_key[32]; static const struct ssh_cipher *cipher = NULL; @@ -288,32 +282,6 @@ static int ssh_channelfind(void *av, void *bv) { return 0; } -static void s_write (char *buf, int len) { - while (len > 0) { - int i = send (s, buf, len, 0); - noise_ultralight(i); - if (i <= 0) { - bombout(("Lost connection while sending")); - return; - } - if (i > 0) - len -= i, buf += i; - } -} - -static int s_read (char *buf, int len) { - int ret = 0; - while (len > 0) { - int i = recv (s, buf, len, 0); - noise_ultralight(i); - if (i > 0) - len -= i, buf += i, ret += i; - else - return i; - } - return ret; -} - static void c_write (char *buf, int len) { if ((flags & FLAG_STDERR)) { int i; @@ -544,19 +512,6 @@ next_packet: crFinish(0); } -static void ssh_gotdata(unsigned char *data, int datalen) -{ - while (datalen > 0) { - if ( s_rdpkt(&data, &datalen) == 0 ) { - ssh_protocol(NULL, 0, 1); - if (ssh_state == SSH_STATE_CLOSED) { - return; - } - } - } -} - - static void s_wrpkt_start(int type, int len) { int pad, biglen; @@ -608,7 +563,7 @@ static void s_wrpkt(void) { if (cipher) cipher->encrypt(pktout.data+4, biglen); - s_write(pktout.data, biglen+4); + sk_write(s, pktout.data, biglen+4); } /* @@ -695,109 +650,6 @@ static void send_packet(int pkttype, ...) s_wrpkt(); } - -/* - * Connect to specified host and port. - * Returns an error message, or NULL on success. - * Also places the canonical host name into `realhost'. - */ -static char *connect_to_host(char *host, int port, char **realhost) -{ - SOCKADDR_IN addr; - struct hostent *h; - unsigned long a; -#ifdef FWHACK - char *FWhost; - int FWport; -#endif - - savedhost = malloc(1+strlen(host)); - if (!savedhost) - fatalbox("Out of memory"); - strcpy(savedhost, host); - - if (port < 0) - port = 22; /* default ssh port */ - savedport = port; - -#ifdef FWHACK - FWhost = host; - FWport = port; - host = FWSTR; - port = 23; -#endif - - /* - * Try to find host. - */ - if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) { - if ( (h = gethostbyname(host)) == NULL) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - case WSAHOST_NOT_FOUND: case WSANO_DATA: - return "Host does not exist"; - case WSATRY_AGAIN: return "Host not found"; - default: return "gethostbyname: unknown error"; - } - memcpy (&a, h->h_addr, sizeof(a)); - *realhost = h->h_name; - } else - *realhost = host; -#ifdef FWHACK - *realhost = FWhost; -#endif - a = ntohl(a); - - /* - * Open socket. - */ - s = socket(AF_INET, SOCK_STREAM, 0); - if (s == INVALID_SOCKET) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - case WSAEAFNOSUPPORT: return "TCP/IP support not present"; - default: return "socket(): unknown error"; - } - - /* - * Bind to local address. - */ - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - addr.sin_port = htons(0); - if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - default: return "bind(): unknown error"; - } - - /* - * Connect to remote address. - */ - addr.sin_addr.s_addr = htonl(a); - addr.sin_port = htons((short)port); - if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - case WSAECONNREFUSED: return "Connection refused"; - case WSAENETUNREACH: return "Network is unreachable"; - case WSAEHOSTUNREACH: return "No route to host"; - default: return "connect(): unknown error"; - } - -#ifdef FWHACK - send(s, "connect ", 8, 0); - send(s, FWhost, strlen(FWhost), 0); - { - char buf[20]; - sprintf(buf, " %d\n", FWport); - send (s, buf, strlen(buf), 0); - } -#endif - - return NULL; -} - static int ssh_versioncmp(char *a, char *b) { char *ae, *be; unsigned long av, bv; @@ -931,7 +783,7 @@ static void ssh2_pkt_send(void) { cscipher->encrypt(pktout.data, pktout.length + padding); maclen = csmac ? csmac->len : 0; - s_write(pktout.data, pktout.length + padding + maclen); + sk_write(s, pktout.data, pktout.length + padding + maclen); } #if 0 @@ -1000,33 +852,35 @@ static Bignum ssh2_pkt_getmp(void) { return b; } -static int do_ssh_init(void) { - char c, *vsp; - char version[10]; - char vstring[80]; - char vlog[sizeof(vstring)+20]; - int i; +static int do_ssh_init(unsigned char c) { + static char *vsp; + static char version[10]; + static char vstring[80]; + static char vlog[sizeof(vstring)+20]; + static int i; -#ifdef FWHACK + crBegin; + + /* Search for the string "SSH-" in the input. */ i = 0; - while (s_read(&c, 1) == 1) { - if (c == 'S' && i < 2) i++; - else if (c == 'S' && i == 2) i = 2; - else if (c == 'H' && i == 2) break; + while (1) { + static const int transS[] = { 1, 2, 2, 1 }; + static const int transH[] = { 0, 0, 3, 0 }; + static const int transminus[] = { 0, 0, 0, -1 }; + if (c == 'S') i = transS[i]; + else if (c == 'H') i = transH[i]; + else if (c == '-') i = transminus[i]; else i = 0; + if (i < 0) + break; + crReturn(1); /* get another character */ } -#else - if (s_read(&c,1) != 1 || c != 'S') return 0; - if (s_read(&c,1) != 1 || c != 'S') return 0; - if (s_read(&c,1) != 1 || c != 'H') return 0; -#endif + strcpy(vstring, "SSH-"); vsp = vstring+4; - if (s_read(&c,1) != 1 || c != '-') return 0; i = 0; while (1) { - if (s_read(&c,1) != 1) - return 0; + crReturn(1); /* get another char */ if (vsp < vstring+sizeof(vstring)-1) *vsp++ = c; if (i >= 0) { @@ -1066,7 +920,7 @@ static int do_ssh_init(void) { sprintf(vlog, "We claim version: %s", verstring); logevent(vlog); logevent("Using SSH protocol version 2"); - s_write(vstring, strlen(vstring)); + sk_write(s, vstring, strlen(vstring)); ssh_protocol = ssh2_protocol; ssh_version = 2; s_rdpkt = ssh2_rdpkt; @@ -1080,16 +934,130 @@ static int do_ssh_init(void) { vlog[strcspn(vlog, "\r\n")] = '\0'; logevent(vlog); logevent("Using SSH protocol version 1"); - s_write(vstring, strlen(vstring)); + sk_write(s, vstring, strlen(vstring)); ssh_protocol = ssh1_protocol; ssh_version = 1; s_rdpkt = ssh1_rdpkt; } - ssh_send_ok = 0; + + crFinish(0); +} + +static void ssh_gotdata(unsigned char *data, int datalen) +{ + crBegin; + + /* + * To begin with, feed the characters one by one to the + * protocol initialisation / selection function do_ssh_init(). + * When that returns 0, we're done with the initial greeting + * exchange and can move on to packet discipline. + */ + while (1) { + int ret; + if (datalen == 0) + crReturnV; /* more data please */ + ret = do_ssh_init(*data); + data++; datalen--; + if (ret == 0) + break; + } + + /* + * We emerge from that loop when the initial negotiation is + * over and we have selected an s_rdpkt function. Now pass + * everything to s_rdpkt, and then pass the resulting packets + * to the proper protocol handler. + */ + if (datalen == 0) + crReturnV; + while (1) { + while (datalen > 0) { + if ( s_rdpkt(&data, &datalen) == 0 ) { + ssh_protocol(NULL, 0, 1); + if (ssh_state == SSH_STATE_CLOSED) { + return; + } + } + } + crReturnV; + } + crFinishV; +} + +static int ssh_receive(Socket s, int urgent, char *data, int len) { + if (!len) { + /* Connection has closed. */ + sk_close(s); + s = NULL; + return 0; + } + ssh_gotdata (data, len); return 1; } /* + * Connect to specified host and port. + * Returns an error message, or NULL on success. + * Also places the canonical host name into `realhost'. + */ +static char *connect_to_host(char *host, int port, char **realhost) +{ + SockAddr addr; + char *err; +#ifdef FWHACK + char *FWhost; + int FWport; +#endif + + savedhost = malloc(1+strlen(host)); + if (!savedhost) + fatalbox("Out of memory"); + strcpy(savedhost, host); + + if (port < 0) + port = 22; /* default ssh port */ + savedport = port; + +#ifdef FWHACK + FWhost = host; + FWport = port; + host = FWSTR; + port = 23; +#endif + + /* + * Try to find host. + */ + addr = sk_namelookup(host, realhost); + if ( (err = sk_addr_error(addr)) ) + return err; + +#ifdef FWHACK + *realhost = FWhost; +#endif + + /* + * Open socket. + */ + s = sk_new(addr, port, ssh_receive); + if ( (err = sk_socket_error(s)) ) + return err; + +#ifdef FWHACK + sk_write(s, "connect ", 8); + sk_write(s, FWhost, strlen(FWhost)); + { + char buf[20]; + sprintf(buf, " %d\n", FWport); + sk_write(s, buf, strlen(buf)); + } +#endif + + return NULL; +} + +/* * Handle the key exchange and user authentication phases. */ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) @@ -1775,8 +1743,13 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) { crReturnV; } } else { - send_packet(SSH1_CMSG_STDIN_DATA, - PKT_INT, inlen, PKT_DATA, in, inlen, PKT_END); + while (inlen > 0) { + int len = min(inlen, 512); + send_packet(SSH1_CMSG_STDIN_DATA, + PKT_INT, len, PKT_DATA, in, len, PKT_END); + in += len; + inlen -= len; + } } } @@ -2441,8 +2414,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) ssh2_pkt_init(SSH2_MSG_DISCONNECT); ssh2_pkt_send(); ssh_state = SSH_STATE_CLOSED; - closesocket(s); - s = INVALID_SOCKET; + sk_close(s); + s = NULL; } continue; /* remote sends close; ignore (FIXME) */ } else if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) { @@ -2510,13 +2483,11 @@ static void ssh2_protocol(unsigned char *in, int inlen, int ispkt) } /* - * Called to set up the connection. Will arrange for WM_NETEVENT - * messages to be passed to the specified window, whose window - * procedure should then call telnet_msg(). + * Called to set up the connection. * * Returns an error message, or NULL on success. */ -static char *ssh_init (HWND hwnd, char *host, int port, char **realhost) { +static char *ssh_init (char *host, int port, char **realhost) { char *p; #ifdef MSCRYPTOAPI @@ -2524,77 +2495,20 @@ static char *ssh_init (HWND hwnd, char *host, int port, char **realhost) { return "Microsoft high encryption pack not installed!"; #endif + ssh_send_ok = 0; + p = connect_to_host(host, port, realhost); if (p != NULL) return p; - if (!do_ssh_init()) - return "Protocol initialisation error"; - - if (hwnd && WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ | FD_CLOSE) == SOCKET_ERROR) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - default: return "WSAAsyncSelect(): unknown error"; - } - return NULL; } /* - * Process a WM_NETEVENT message. Will return 0 if the connection - * has closed, or <0 for a socket error. - */ -static int ssh_msg (WPARAM wParam, LPARAM lParam) { - int ret; - char buf[256]; - - /* - * Because reading less than the whole of the available pending - * data can generate an FD_READ event, we need to allow for the - * possibility that FD_READ may arrive with FD_CLOSE already in - * the queue; so it's possible that we can get here even with s - * invalid. If so, we return 1 and don't worry about it. - */ - if (s == INVALID_SOCKET) - return 1; - - if (WSAGETSELECTERROR(lParam) != 0) { - closesocket(s); - s = INVALID_SOCKET; - return -WSAGETSELECTERROR(lParam); - } - - switch (WSAGETSELECTEVENT(lParam)) { - case FD_READ: - case FD_CLOSE: - ret = recv(s, buf, sizeof(buf), 0); - if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK) - return 1; - if (ret < 0) { /* any _other_ error */ - closesocket(s); - s = INVALID_SOCKET; - return -10000-WSAGetLastError(); - } - if (ret == 0) { - s = INVALID_SOCKET; - return 0; - } - ssh_gotdata (buf, ret); - if (ssh_state == SSH_STATE_CLOSED) { - closesocket(s); - s = INVALID_SOCKET; - return 0; - } - return 1; - } - return 1; /* shouldn't happen, but WTF */ -} - -/* * Called to send data down the Telnet connection. */ static void ssh_send (char *buf, int len) { - if (s == INVALID_SOCKET) + if (s == NULL) return; ssh_protocol(buf, len, 0); @@ -2648,13 +2562,12 @@ static void ssh_special (Telnet_Special code) { } } -static SOCKET ssh_socket(void) { return s; } +static Socket ssh_socket(void) { return s; } static int ssh_sendok(void) { return ssh_send_ok; } Backend ssh_backend = { ssh_init, - ssh_msg, ssh_send, ssh_size, ssh_special, diff --git a/telnet.c b/telnet.c index 7b6c0bf6..ff6681f6 100644 --- a/telnet.c +++ b/telnet.c @@ -1,13 +1,6 @@ #include #include #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include "putty.h" @@ -18,7 +11,7 @@ #define TRUE 1 #endif -static SOCKET s = INVALID_SOCKET; +static Socket s = NULL; #define IAC 255 /* interpret as command: */ #define DONT 254 /* you are not to use option */ @@ -145,32 +138,6 @@ static char *sb_buf = NULL; static int sb_size = 0; #define SB_DELTA 1024 -static void try_write (void) { - while (outbuf_head != outbuf_reap) { - int end = (outbuf_reap < outbuf_head ? outbuf_head : OUTBUF_SIZE); - int len = end - outbuf_reap; - int ret; - - ret = send (s, outbuf+outbuf_reap, len, 0); - if (ret > 0) - outbuf_reap = (outbuf_reap + ret) & OUTBUF_MASK; - if (ret < len) - return; - } -} - -static void s_write (void *buf, int len) { - unsigned char *p = buf; - while (len--) { - int new_head = (outbuf_head + 1) & OUTBUF_MASK; - if (new_head != outbuf_reap) { - outbuf[outbuf_head] = *p++; - outbuf_head = new_head; - } - } - try_write(); -} - static void c_write1(int c) { char cc = (char)c; from_backend(0, &cc, 1); @@ -189,7 +156,7 @@ static void send_opt (int cmd, int option) { unsigned char b[3]; b[0] = IAC; b[1] = cmd; b[2] = option; - s_write (b, 3); + sk_write(s, b, 3); log_option("client", cmd, option); } @@ -286,7 +253,7 @@ static void process_subneg (void) { strcpy(b+4, cfg.termspeed); n = 4 + strlen(cfg.termspeed); b[n] = IAC; b[n+1] = SE; - s_write (b, n+2); + sk_write(s, b, n+2); logevent("server:\tSB TSPEED SEND"); sprintf(logbuf, "client:\tSB TSPEED IS %s", cfg.termspeed); logevent (logbuf); @@ -302,7 +269,7 @@ static void process_subneg (void) { b[n+4] = (cfg.termtype[n] >= 'a' && cfg.termtype[n] <= 'z' ? cfg.termtype[n] + 'A'-'a' : cfg.termtype[n]); b[n+4] = IAC; b[n+5] = SE; - s_write (b, n+6); + sk_write(s, b, n+6); b[n+4] = 0; logevent("server:\tSB TTYPE SEND"); sprintf(logbuf, "client:\tSB TTYPE IS %s", b+4); @@ -367,7 +334,7 @@ static void process_subneg (void) { while (*e) b[n++] = *e++; } b[n++] = IAC; b[n++] = SE; - s_write (b, n); + sk_write(s, b, n); sprintf(logbuf, "client:\tSB %s IS %s", telopt(sb_opt), n==6 ? "" : ""); logevent (logbuf); @@ -486,37 +453,34 @@ static void do_telnet_read (char *buf, int len) { } } +static int telnet_receive(Socket s, int urgent, char *data, int len) { + if (!len) { + /* Connection has closed. */ + sk_close(s); + s = NULL; + return 0; + } + do_telnet_read (data, len); + return 1; +} + /* - * Called to set up the Telnet connection. Will arrange for - * WM_NETEVENT messages to be passed to the specified window, whose - * window procedure should then call telnet_msg(). + * Called to set up the Telnet connection. * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. */ -static char *telnet_init (HWND hwnd, char *host, int port, char **realhost) { - SOCKADDR_IN addr; - struct hostent *h; - unsigned long a; +static char *telnet_init (char *host, int port, char **realhost) { + SockAddr addr; + char *err; /* * Try to find host. */ - if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) { - if ( (h = gethostbyname(host)) == NULL) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - case WSAHOST_NOT_FOUND: case WSANO_DATA: - return "Host does not exist"; - case WSATRY_AGAIN: return "Host not found"; - default: return "gethostbyname: unknown error"; - } - memcpy (&a, h->h_addr, sizeof(a)); - *realhost = h->h_name; - } else - *realhost = host; - a = ntohl(a); + addr = sk_namelookup(host, realhost); + if ( (err = sk_addr_error(addr)) ) + return err; if (port < 0) port = 23; /* default telnet port */ @@ -524,51 +488,11 @@ static char *telnet_init (HWND hwnd, char *host, int port, char **realhost) { /* * Open socket. */ - s = socket(AF_INET, SOCK_STREAM, 0); - if (s == INVALID_SOCKET) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - case WSAEAFNOSUPPORT: return "TCP/IP support not present"; - default: return "socket(): unknown error"; - } + s = sk_new(addr, port, telnet_receive); + if ( (err = sk_socket_error(s)) ) + return err; - { - BOOL b = TRUE; - setsockopt (s, SOL_SOCKET, SO_OOBINLINE, (void *)&b, sizeof(b)); - } - - /* - * Bind to local address. - */ - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - addr.sin_port = htons(0); - if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - default: return "bind(): unknown error"; - } - - /* - * Connect to remote address. - */ - addr.sin_addr.s_addr = htonl(a); - addr.sin_port = htons((short)port); - if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - case WSAECONNREFUSED: return "Connection refused"; - case WSAENETUNREACH: return "Network is unreachable"; - case WSAEHOSTUNREACH: return "No route to host"; - default: return "connect(): unknown error"; - } - - if (hwnd && WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ | - FD_WRITE | FD_OOB | FD_CLOSE) == SOCKET_ERROR) - switch (WSAGetLastError()) { - case WSAENETDOWN: return "Network is down"; - default: return "WSAAsyncSelect(): unknown error"; - } + sk_addr_free(addr); /* * Initialise option states. @@ -604,72 +528,6 @@ static char *telnet_init (HWND hwnd, char *host, int port, char **realhost) { } /* - * Process a WM_NETEVENT message. Will return 0 if the connection - * has closed, or <0 for a socket error. - */ -static int telnet_msg (WPARAM wParam, LPARAM lParam) { - int ret; - /* This needs to be larger than the packet size now that inbuf - * cannot overflow, in fact the fewer calls we make to windows - * the faster we will run! - */ - char buf[16384]; - - /* - * Because reading less than the whole of the available pending - * data can generate an FD_READ event, we need to allow for the - * possibility that FD_READ may arrive with FD_CLOSE already in - * the queue; so it's possible that we can get here even with s - * invalid. If so, we return 1 and don't worry about it. - */ - if (s == INVALID_SOCKET) - return 1; - - if (WSAGETSELECTERROR(lParam) != 0) { - closesocket(s); - s = INVALID_SOCKET; - return -WSAGETSELECTERROR(lParam); - } - - switch (WSAGETSELECTEVENT(lParam)) { - case FD_READ: - case FD_CLOSE: - { - int clear_of_oob = 1; - - /* Don't check for error return; some shims don't support - * this ioctl. - */ - ioctlsocket (s, SIOCATMARK, &clear_of_oob); - - in_synch = !clear_of_oob; - - do { - ret = recv(s, buf, sizeof(buf), 0); - if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK) - return 1; - if (ret < 0) { /* any _other_ error */ - closesocket(s); - s = INVALID_SOCKET; - return -10000-WSAGetLastError(); - } - if (ret == 0) { - s = INVALID_SOCKET; - return 0; - } - do_telnet_read (buf, ret); - } while (in_synch); - } - return 1; - case FD_WRITE: - if (outbuf_head != outbuf_reap) - try_write(); - return 1; - } - return 1; /* shouldn't happen, but WTF */ -} - -/* * Called to send data down the Telnet connection. */ static void telnet_send (char *buf, int len) { @@ -678,7 +536,7 @@ static void telnet_send (char *buf, int len) { static unsigned char cr[2] = { CR, NUL }; static unsigned char nl[2] = { CR, LF }; - if (s == INVALID_SOCKET) + if (s == NULL) return; p = buf; @@ -686,10 +544,10 @@ static void telnet_send (char *buf, int len) { char *q = p; while (iswritable((unsigned char)*p) && p < buf+len) p++; - s_write (q, p-q); + sk_write(s, q, p-q); while (p < buf+len && !iswritable((unsigned char)*p)) { - s_write ((unsigned char)*p == IAC ? iac : nl, 2); + sk_write(s, (unsigned char)*p == IAC ? iac : nl, 2); p++; } } @@ -702,13 +560,13 @@ static void telnet_size(void) { unsigned char b[16]; char logbuf[50]; - if (s == INVALID_SOCKET || o_naws.state != ACTIVE) + if (s == NULL || o_naws.state != ACTIVE) return; b[0] = IAC; b[1] = SB; b[2] = TELOPT_NAWS; b[3] = cols >> 8; b[4] = cols & 0xFF; b[5] = rows >> 8; b[6] = rows & 0xFF; b[7] = IAC; b[8] = SE; - s_write (b, 9); + sk_write(s, b, 9); sprintf(logbuf, "client:\tSB NAWS %d,%d", ((unsigned char)b[3] << 8) + (unsigned char)b[4], ((unsigned char)b[5] << 8) + (unsigned char)b[6]); @@ -721,28 +579,28 @@ static void telnet_size(void) { static void telnet_special (Telnet_Special code) { unsigned char b[2]; - if (s == INVALID_SOCKET) + if (s == NULL) return; b[0] = IAC; switch (code) { - case TS_AYT: b[1] = AYT; s_write (b, 2); break; - case TS_BRK: b[1] = BREAK; s_write (b, 2); break; - case TS_EC: b[1] = EC; s_write (b, 2); break; - case TS_EL: b[1] = EL; s_write (b, 2); break; - case TS_GA: b[1] = GA; s_write (b, 2); break; - case TS_NOP: b[1] = NOP; s_write (b, 2); break; - case TS_ABORT: b[1] = ABORT; s_write (b, 2); break; - case TS_AO: b[1] = AO; s_write (b, 2); break; - case TS_IP: b[1] = IP; s_write (b, 2); break; - case TS_SUSP: b[1] = SUSP; s_write (b, 2); break; - case TS_EOR: b[1] = EOR; s_write (b, 2); break; - case TS_EOF: b[1] = xEOF; s_write (b, 2); break; + case TS_AYT: b[1] = AYT; sk_write(s, b, 2); break; + case TS_BRK: b[1] = BREAK; sk_write(s, b, 2); break; + case TS_EC: b[1] = EC; sk_write(s, b, 2); break; + case TS_EL: b[1] = EL; sk_write(s, b, 2); break; + case TS_GA: b[1] = GA; sk_write(s, b, 2); break; + case TS_NOP: b[1] = NOP; sk_write(s, b, 2); break; + case TS_ABORT: b[1] = ABORT; sk_write(s, b, 2); break; + case TS_AO: b[1] = AO; sk_write(s, b, 2); break; + case TS_IP: b[1] = IP; sk_write(s, b, 2); break; + case TS_SUSP: b[1] = SUSP; sk_write(s, b, 2); break; + case TS_EOR: b[1] = EOR; sk_write(s, b, 2); break; + case TS_EOF: b[1] = xEOF; sk_write(s, b, 2); break; case TS_SYNCH: - outbuf_head = outbuf_reap = 0; - b[1] = DM; - send (s, b, 2, MSG_OOB); - break; + b[1] = DM; + sk_write (s, b, 1); + sk_write_oob (s, b+1, 1); + break; case TS_RECHO: if (o_echo.state == INACTIVE || o_echo.state == REALLY_INACTIVE) { o_echo.state = REQUESTED; @@ -758,19 +616,18 @@ static void telnet_special (Telnet_Special code) { case TS_PING: if (o_they_sga.state == ACTIVE) { b[1] = NOP; - s_write (b, 2); + sk_write(s, b, 2); } break; } } -static SOCKET telnet_socket(void) { return s; } +static Socket telnet_socket(void) { return s; } static int telnet_sendok(void) { return 1; } Backend telnet_backend = { telnet_init, - telnet_msg, telnet_send, telnet_size, telnet_special, diff --git a/terminal.c b/terminal.c index c1fef2a1..12ad1e9c 100644 --- a/terminal.c +++ b/terminal.c @@ -1,11 +1,4 @@ #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include #include @@ -2150,7 +2143,7 @@ void term_nopaste() { } void term_paste() { -static long last_paste = 0; + static long last_paste = 0; long now, paste_diff; if(paste_len == 0) return; @@ -2166,10 +2159,15 @@ static long last_paste = 0; while(paste_possend (&c, 1); + int n = 0; + while (n + paste_pos < paste_len) { + if (paste_buffer[paste_pos + n++] == '\r') + break; + } + ldisc->send (paste_buffer+paste_pos, n); + paste_pos += n; - if (c =='\r') { + if (paste_pos < paste_len) { paste_hold = 1; return; } diff --git a/windlg.c b/windlg.c index 6a45a31a..d338781f 100644 --- a/windlg.c +++ b/windlg.c @@ -1,13 +1,6 @@ #include #include #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include #include diff --git a/window.c b/window.c index 7db845e4..1e38a487 100644 --- a/window.c +++ b/window.c @@ -129,6 +129,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { return 1; } /* WISHLIST: maybe allow config tweaking even if winsock not present? */ + sk_init(); InitCommonControls(); @@ -435,7 +436,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { char msg[1024], *title; char *realhost; - error = back->init (hwnd, cfg.host, cfg.port, &realhost); + error = back->init (cfg.host, cfg.port, &realhost); if (error) { sprintf(msg, "Unable to open connection:\n%s", error); MessageBox(NULL, msg, "PuTTY Error", MB_ICONERROR | MB_OK); @@ -624,6 +625,28 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { } /* + * Set up, or shut down, an AsyncSelect. Called from winnet.c. + */ +char *do_select(SOCKET skt, int startup) { + int msg, events; + if (startup) { + msg = WM_NETEVENT; + events = FD_READ | FD_WRITE | FD_OOB | FD_CLOSE; + } else { + msg = events = 0; + } + if (!hwnd) + return "do_select(): internal error (hwnd==NULL)"; + if (WSAAsyncSelect (skt, hwnd, msg, events) == SOCKET_ERROR) { + switch (WSAGetLastError()) { + case WSAENETDOWN: return "Network is down"; + default: return "WSAAsyncSelect(): unknown error"; + } + } + return NULL; +} + +/* * Print a message box and close the connection. */ void connection_fatal(char *fmt, ...) { @@ -646,8 +669,9 @@ void connection_fatal(char *fmt, ...) { * Actually do the job requested by a WM_NETEVENT */ static void enact_pending_netevent(void) { - int i; static int reentering = 0; + extern int select_result(WPARAM, LPARAM); + int ret; if (reentering) return; /* don't unpend the pending */ @@ -655,25 +679,10 @@ static void enact_pending_netevent(void) { pending_netevent = FALSE; reentering = 1; - i = back->msg (pend_netevent_wParam, pend_netevent_lParam); + ret = select_result (pend_netevent_wParam, pend_netevent_lParam); reentering = 0; - if (i < 0) { - char buf[1024]; - switch (WSABASEERR + (-i) % 10000) { - case WSAECONNRESET: - sprintf(buf, "Connection reset by peer"); - break; - case WSAECONNABORTED: - sprintf(buf, "Connection aborted"); - break; - default: - sprintf(buf, "Unexpected network error %d", -i); - break; - } - connection_fatal(buf); - } - if (i <= 0) { + if (ret == 0) { if (cfg.close_on_exit) PostQuitMessage(0); else { diff --git a/winstore.c b/winstore.c index 51f4ee7a..55977648 100644 --- a/winstore.c +++ b/winstore.c @@ -4,13 +4,6 @@ */ #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include #include "putty.h" #include "storage.h" diff --git a/xlat.c b/xlat.c index 535497d6..092f5cab 100644 --- a/xlat.c +++ b/xlat.c @@ -1,11 +1,4 @@ #include -#ifndef AUTO_WINSOCK -#ifdef WINSOCK_TWO -#include -#else -#include -#endif -#endif #include #include "putty.h" -- 2.11.0