Created a shiny new abstraction for the socket handling. Has many
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Mon, 23 Oct 2000 10:32:37 +0000 (10:32 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Mon, 23 Oct 2000 10:32:37 +0000 (10:32 +0000)
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.

git-svn-id: svn://svn.tartarus.org/sgt/putty@744 cda61777-01e9-0310-a592-d414129be87e

20 files changed:
Makefile
be_all.c
be_none.c
be_nossh.c
ldisc.c
misc.c
noise.c
plink.c
putty.h
raw.c
scp.c
settings.c
sizetip.c
ssh.c
telnet.c
terminal.c
windlg.c
window.c
winstore.c
xlat.c

index 4e20f61..27f72bb 100644 (file)
--- 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
 ##--
index ae58771..69e44b7 100644 (file)
--- a/be_all.c
+++ b/be_all.c
@@ -4,13 +4,6 @@
  */
 
 #include <windows.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#endif
-#endif
 #include <stdio.h>
 #include "putty.h"
 
index 8151b3d..d112143 100644 (file)
--- a/be_none.c
+++ b/be_none.c
@@ -5,13 +5,6 @@
  */
 
 #include <windows.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#endif
-#endif
 #include <stdio.h>
 #include "putty.h"
 
index 5dac276..fdd9828 100644 (file)
@@ -4,13 +4,6 @@
  */
 
 #include <windows.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#endif
-#endif
 #include <stdio.h>
 #include "putty.h"
 
diff --git a/ldisc.c b/ldisc.c
index 10576d2..80659cc 100644 (file)
--- a/ldisc.c
+++ b/ldisc.c
@@ -1,11 +1,4 @@
 #include <windows.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#endif
-#endif
 #include <stdio.h>
 #include <ctype.h>
 
diff --git a/misc.c b/misc.c
index e06ced6..6bb09c5 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -1,11 +1,4 @@
 #include <windows.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#endif
-#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include "putty.h"
diff --git a/noise.c b/noise.c
index 1d764d5..af75f9d 100644 (file)
--- a/noise.c
+++ b/noise.c
@@ -4,13 +4,6 @@
  */
 
 #include <windows.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#endif
-#endif
 #include <stdio.h>
 
 #include "putty.h"
diff --git a/plink.c b/plink.c
index 26a1729..f5f6c8a 100644 (file)
--- 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 7f14f3d..ae936b0 100644 (file)
--- 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 3f82d7a..833f843 100644 (file)
--- a/raw.c
+++ b/raw.c
@@ -1,13 +1,6 @@
 #include <windows.h>
 #include <stdio.h>
 #include <stdlib.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#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 401d444..81f925b 100644 (file)
--- 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] != '-')
index a541441..e762aba 100644 (file)
@@ -3,13 +3,6 @@
  */
 
 #include <windows.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#endif
-#endif
 #include <stdio.h>
 #include "putty.h"
 #include "storage.h"
index 439d88c..10bdee5 100644 (file)
--- a/sizetip.c
+++ b/sizetip.c
@@ -1,11 +1,4 @@
 #include <windows.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#endif
-#endif
 #include <winreg.h>
 #include <tchar.h>
 #include <stdio.h>
diff --git a/ssh.c b/ssh.c
index c065f2f..744c86d 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -1,14 +1,8 @@
+#include <windows.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <assert.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#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,
index 7b6c0bf..ff6681f 100644 (file)
--- a/telnet.c
+++ b/telnet.c
@@ -1,13 +1,6 @@
 #include <windows.h>
 #include <stdio.h>
 #include <stdlib.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#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 ? "<nothing>" : "<stuff>");
            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,
index c1fef2a..12ad1e9 100644 (file)
@@ -1,11 +1,4 @@
 #include <windows.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#endif
-#endif
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -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_pos<paste_len)
     {
-       char c = paste_buffer[paste_pos++];
-       ldisc->send (&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;
        }
index 6a45a31..d338781 100644 (file)
--- a/windlg.c
+++ b/windlg.c
@@ -1,13 +1,6 @@
 #include <windows.h>
 #include <commctrl.h>
 #include <commdlg.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#endif
-#endif
 #include <stdio.h>
 #include <stdlib.h>
 
index 7db845e..1e38a48 100644 (file)
--- 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 {
index 51f4ee7..5597764 100644 (file)
@@ -4,13 +4,6 @@
  */
 
 #include <windows.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#endif
-#endif
 #include <stdio.h>
 #include "putty.h"
 #include "storage.h"
diff --git a/xlat.c b/xlat.c
index 535497d..092f5ca 100644 (file)
--- a/xlat.c
+++ b/xlat.c
@@ -1,11 +1,4 @@
 #include <windows.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#endif
-#endif
 #include <stdio.h>
 #include "putty.h"