]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - winnet.c
Due to fears that an incompetent WinSock might allow localhost-
[PuTTY.git] / winnet.c
1 /*
2  * Windows networking abstraction.
3  *
4  * Due to this clean abstraction it was possible
5  * to easily implement IPv6 support :)
6  *
7  * IPv6 patch 1 (27 October 2000) Jeroen Massar <jeroen@unfix.org>
8  *  - Preliminary hacked IPv6 support.
9  *    - Connecting to IPv6 address (eg fec0:4242:4242:100:2d0:b7ff:fe8f:5d42) works.
10  *    - Connecting to IPv6 hostname (eg heaven.ipv6.unfix.org) works.
11  *  - Compiles as either IPv4 or IPv6.
12  *
13  * IPv6 patch 2 (29 October 2000) Jeroen Massar <jeroen@unfix.org>
14  *  - When compiled as IPv6 it also allows connecting to IPv4 hosts.
15  *  - Added some more documentation.
16  *
17  * IPv6 patch 3 (18 November 2000) Jeroen Massar <jeroen@unfix.org>
18  *  - It now supports dynamically loading the IPv6 resolver dll's.
19  *    This way we should be able to distribute one (1) binary
20  *    which supports both IPv4 and IPv6.
21  *  - getaddrinfo() and getnameinfo() are loaded dynamicaly if possible.
22  *  - in6addr_any is defined in this file so we don't need to link to wship6.lib
23  *  - The patch is now more unified so that we can still
24  *    remove all IPv6 support by undef'ing IPV6.
25  *    But where it fallsback to IPv4 it uses the IPv4 code which is already in place...
26  *  - Canonical name resolving works.
27  *
28  * IPv6 patch 4 (07 January 2001) Jeroen Massar <jeroen@unfix.org>
29  *  - patch against CVS of today, will be submitted to the bugs list
30  *    as a 'cvs diff -u' on Simon's request...
31  *
32  */
33
34 /*
35  * Define IPV6 to have IPv6 on-the-fly-loading support.
36  * This means that one doesn't have to have an IPv6 stack to use it.
37  * But if an IPv6 stack is found it is used with a fallback to IPv4.
38  */
39 /* #define IPV6 1 */
40
41 #ifdef IPV6
42 #include <winsock2.h>
43 #include <ws2tcpip.h>
44 #include <tpipv6.h>
45 #else
46 #include <winsock.h>
47 #endif
48 #include <windows.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <assert.h>
52
53 #define DEFINE_PLUG_METHOD_MACROS
54 #include "putty.h"
55 #include "network.h"
56 #include "tree234.h"
57
58 struct Socket_tag {
59     struct socket_function_table *fn;
60     /* the above variable absolutely *must* be the first in this structure */
61     char *error;
62     SOCKET s;
63     Plug plug;
64     void *private_ptr;
65     bufchain output_data;
66     int connected;
67     int writable;
68     int frozen; /* this causes readability notifications to be ignored */
69     int frozen_readable; /* this means we missed at least one readability
70                           * notification while we were frozen */
71     int localhost_only;                /* for listening sockets */
72     char oobdata[1];
73     int sending_oob;
74     int oobinline;
75 };
76
77 /*
78  * We used to typedef struct Socket_tag *Socket.
79  *
80  * Since we have made the networking abstraction slightly more
81  * abstract, Socket no longer means a tcp socket (it could mean
82  * an ssl socket).  So now we must use Actual_Socket when we know
83  * we are talking about a tcp socket.
84  */
85 typedef struct Socket_tag *Actual_Socket;
86
87 struct SockAddr_tag {
88     char *error;
89     /* address family this belongs to, AF_INET for IPv4, AF_INET6 for IPv6. */
90     int family;
91     unsigned long address;             /* Address IPv4 style. */
92 #ifdef IPV6
93     struct addrinfo *ai;               /* Address IPv6 style. */
94 #endif
95 };
96
97 static tree234 *sktree;
98
99 static int cmpfortree(void *av, void *bv)
100 {
101     Actual_Socket a = (Actual_Socket) av, b = (Actual_Socket) bv;
102     unsigned long as = (unsigned long) a->s, bs = (unsigned long) b->s;
103     if (as < bs)
104         return -1;
105     if (as > bs)
106         return +1;
107     return 0;
108 }
109
110 static int cmpforsearch(void *av, void *bv)
111 {
112     Actual_Socket b = (Actual_Socket) bv;
113     unsigned long as = (unsigned long) av, bs = (unsigned long) b->s;
114     if (as < bs)
115         return -1;
116     if (as > bs)
117         return +1;
118     return 0;
119 }
120
121 void sk_init(void)
122 {
123     sktree = newtree234(cmpfortree);
124 }
125
126 char *winsock_error_string(int error)
127 {
128     switch (error) {
129       case WSAEACCES:
130         return "Network error: Permission denied";
131       case WSAEADDRINUSE:
132         return "Network error: Address already in use";
133       case WSAEADDRNOTAVAIL:
134         return "Network error: Cannot assign requested address";
135       case WSAEAFNOSUPPORT:
136         return
137             "Network error: Address family not supported by protocol family";
138       case WSAEALREADY:
139         return "Network error: Operation already in progress";
140       case WSAECONNABORTED:
141         return "Network error: Software caused connection abort";
142       case WSAECONNREFUSED:
143         return "Network error: Connection refused";
144       case WSAECONNRESET:
145         return "Network error: Connection reset by peer";
146       case WSAEDESTADDRREQ:
147         return "Network error: Destination address required";
148       case WSAEFAULT:
149         return "Network error: Bad address";
150       case WSAEHOSTDOWN:
151         return "Network error: Host is down";
152       case WSAEHOSTUNREACH:
153         return "Network error: No route to host";
154       case WSAEINPROGRESS:
155         return "Network error: Operation now in progress";
156       case WSAEINTR:
157         return "Network error: Interrupted function call";
158       case WSAEINVAL:
159         return "Network error: Invalid argument";
160       case WSAEISCONN:
161         return "Network error: Socket is already connected";
162       case WSAEMFILE:
163         return "Network error: Too many open files";
164       case WSAEMSGSIZE:
165         return "Network error: Message too long";
166       case WSAENETDOWN:
167         return "Network error: Network is down";
168       case WSAENETRESET:
169         return "Network error: Network dropped connection on reset";
170       case WSAENETUNREACH:
171         return "Network error: Network is unreachable";
172       case WSAENOBUFS:
173         return "Network error: No buffer space available";
174       case WSAENOPROTOOPT:
175         return "Network error: Bad protocol option";
176       case WSAENOTCONN:
177         return "Network error: Socket is not connected";
178       case WSAENOTSOCK:
179         return "Network error: Socket operation on non-socket";
180       case WSAEOPNOTSUPP:
181         return "Network error: Operation not supported";
182       case WSAEPFNOSUPPORT:
183         return "Network error: Protocol family not supported";
184       case WSAEPROCLIM:
185         return "Network error: Too many processes";
186       case WSAEPROTONOSUPPORT:
187         return "Network error: Protocol not supported";
188       case WSAEPROTOTYPE:
189         return "Network error: Protocol wrong type for socket";
190       case WSAESHUTDOWN:
191         return "Network error: Cannot send after socket shutdown";
192       case WSAESOCKTNOSUPPORT:
193         return "Network error: Socket type not supported";
194       case WSAETIMEDOUT:
195         return "Network error: Connection timed out";
196       case WSAEWOULDBLOCK:
197         return "Network error: Resource temporarily unavailable";
198       case WSAEDISCON:
199         return "Network error: Graceful shutdown in progress";
200       default:
201         return "Unknown network error";
202     }
203 }
204
205 SockAddr sk_namelookup(char *host, char **canonicalname)
206 {
207     SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
208     unsigned long a;
209     struct hostent *h = NULL;
210     char realhost[8192];
211
212     /* Clear the structure and default to IPv4. */
213     memset(ret, 0, sizeof(struct SockAddr_tag));
214     ret->family = 0;                   /* We set this one when we have resolved the host. */
215     *realhost = '\0';
216
217     if ((a = inet_addr(host)) == (unsigned long) INADDR_NONE) {
218 #ifdef IPV6
219
220         /* Try to get the getaddrinfo() function from wship6.dll */
221         /* This way one doesn't need to have IPv6 dll's to use PuTTY and
222          * it will fallback to IPv4. */
223         typedef int (CALLBACK * FGETADDRINFO) (const char *nodename,
224                                                const char *servname,
225                                                const struct addrinfo *
226                                                hints,
227                                                struct addrinfo ** res);
228         FGETADDRINFO fGetAddrInfo = NULL;
229
230         HINSTANCE dllWSHIP6 = LoadLibrary("wship6.dll");
231         if (dllWSHIP6)
232             fGetAddrInfo = (FGETADDRINFO) GetProcAddress(dllWSHIP6,
233                                                          "getaddrinfo");
234
235         /*
236          * Use fGetAddrInfo when it's available (which usually also
237          * means IPv6 is installed...)
238          */
239         if (fGetAddrInfo) {
240             /*debug(("Resolving \"%s\" with getaddrinfo()  (IPv4+IPv6 capable)...\n", host)); */
241             if (fGetAddrInfo(host, NULL, NULL, &ret->ai) == 0)
242                 ret->family = ret->ai->ai_family;
243         } else
244 #endif
245         {
246             /*
247              * Otherwise use the IPv4-only gethostbyname...
248              * (NOTE: we don't use gethostbyname as a
249              * fallback!)
250              */
251             if (ret->family == 0) {
252                 /*debug(("Resolving \"%s\" with gethostbyname() (IPv4 only)...\n", host)); */
253                 if ( (h = gethostbyname(host)) )
254                     ret->family = AF_INET;
255             }
256         }
257         /*debug(("Done resolving...(family is %d) AF_INET = %d, AF_INET6 = %d\n", ret->family, AF_INET, AF_INET6)); */
258
259         if (ret->family == 0) {
260             DWORD err = WSAGetLastError();
261             ret->error = (err == WSAENETDOWN ? "Network is down" :
262                           err ==
263                           WSAHOST_NOT_FOUND ? "Host does not exist" : err
264                           == WSATRY_AGAIN ? "Host not found" :
265 #ifdef IPV6
266                           fGetAddrInfo ? "getaddrinfo: unknown error" :
267 #endif
268                           "gethostbyname: unknown error");
269 #ifdef DEBUG
270             {
271                 LPVOID lpMsgBuf;
272                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
273                               FORMAT_MESSAGE_FROM_SYSTEM |
274                               FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err,
275                               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
276                               (LPTSTR) & lpMsgBuf, 0, NULL);
277                 /*debug(("Error %ld: %s (h=%lx)\n", err, lpMsgBuf, h)); */
278                 /* Free the buffer. */
279                 LocalFree(lpMsgBuf);
280             }
281 #endif
282         } else {
283             ret->error = NULL;
284
285 #ifdef IPV6
286             /* If we got an address info use that... */
287             if (ret->ai) {
288                 typedef int (CALLBACK * FGETNAMEINFO)
289                  (const struct sockaddr FAR * sa, socklen_t salen,
290                   char FAR * host, size_t hostlen, char FAR * serv,
291                   size_t servlen, int flags);
292                 FGETNAMEINFO fGetNameInfo = NULL;
293
294                 /* Are we in IPv4 fallback mode? */
295                 /* We put the IPv4 address into the a variable so we can further-on use the IPv4 code... */
296                 if (ret->family == AF_INET)
297                     memcpy(&a,
298                            (char *) &((SOCKADDR_IN *) ret->ai->
299                                       ai_addr)->sin_addr, sizeof(a));
300
301                 /* Now let's find that canonicalname... */
302                 if ((dllWSHIP6)
303                     && (fGetNameInfo =
304                         (FGETNAMEINFO) GetProcAddress(dllWSHIP6,
305                                                       "getnameinfo"))) {
306                     if (fGetNameInfo
307                         ((struct sockaddr *) ret->ai->ai_addr,
308                          ret->family ==
309                          AF_INET ? sizeof(SOCKADDR_IN) :
310                          sizeof(SOCKADDR_IN6), realhost,
311                          sizeof(realhost), NULL, 0, 0) != 0) {
312                         strncpy(realhost, host, sizeof(realhost));
313                     }
314                 }
315             }
316             /* We used the IPv4-only gethostbyname()... */
317             else
318 #endif
319             {
320                 memcpy(&a, h->h_addr, sizeof(a));
321                 /* This way we are always sure the h->h_name is valid :) */
322                 strncpy(realhost, h->h_name, sizeof(realhost));
323             }
324         }
325 #ifdef IPV6
326         FreeLibrary(dllWSHIP6);
327 #endif
328     } else {
329         /*
330          * This must be a numeric IPv4 address because it caused a
331          * success return from inet_addr.
332          */
333         ret->family = AF_INET;
334         strncpy(realhost, host, sizeof(realhost));
335     }
336     ret->address = ntohl(a);
337     realhost[lenof(realhost)-1] = '\0';
338     *canonicalname = smalloc(1+strlen(realhost));
339     strcpy(*canonicalname, realhost);
340     return ret;
341 }
342
343 void sk_getaddr(SockAddr addr, char *buf, int buflen)
344 {
345 #ifdef IPV6
346     if (addr->family == AF_INET) {
347 #endif
348         struct in_addr a;
349         a.s_addr = htonl(addr->address);
350         strncpy(buf, inet_ntoa(a), buflen);
351 #ifdef IPV6
352     } else {
353         FIXME; /* I don't know how to get a text form of an IPv6 address. */
354     }
355 #endif
356 }
357
358 void sk_addr_free(SockAddr addr)
359 {
360     sfree(addr);
361 }
362
363 static Plug sk_tcp_plug(Socket sock, Plug p)
364 {
365     Actual_Socket s = (Actual_Socket) sock;
366     Plug ret = s->plug;
367     if (p)
368         s->plug = p;
369     return ret;
370 }
371
372 static void sk_tcp_flush(Socket s)
373 {
374     /*
375      * We send data to the socket as soon as we can anyway,
376      * so we don't need to do anything here.  :-)
377      */
378 }
379
380 static void sk_tcp_close(Socket s);
381 static int sk_tcp_write(Socket s, char *data, int len);
382 static int sk_tcp_write_oob(Socket s, char *data, int len);
383 static char *sk_tcp_socket_error(Socket s);
384
385 extern char *do_select(SOCKET skt, int startup);
386
387 Socket sk_register(void *sock, Plug plug)
388 {
389     static struct socket_function_table fn_table = {
390         sk_tcp_plug,
391         sk_tcp_close,
392         sk_tcp_write,
393         sk_tcp_write_oob,
394         sk_tcp_flush,
395         sk_tcp_socket_error
396     };
397
398     DWORD err;
399     char *errstr;
400     Actual_Socket ret;
401
402     /*
403      * Create Socket structure.
404      */
405     ret = smalloc(sizeof(struct Socket_tag));
406     ret->fn = &fn_table;
407     ret->error = NULL;
408     ret->plug = plug;
409     bufchain_init(&ret->output_data);
410     ret->writable = 1;                 /* to start with */
411     ret->sending_oob = 0;
412     ret->frozen = 1;
413     ret->frozen_readable = 0;
414     ret->localhost_only = 0;           /* unused, but best init anyway */
415
416     ret->s = (SOCKET)sock;
417
418     if (ret->s == INVALID_SOCKET) {
419         err = WSAGetLastError();
420         ret->error = winsock_error_string(err);
421         return (Socket) ret;
422     }
423
424     ret->oobinline = 0;
425
426     /* Set up a select mechanism. This could be an AsyncSelect on a
427      * window, or an EventSelect on an event object. */
428     errstr = do_select(ret->s, 1);
429     if (errstr) {
430         ret->error = errstr;
431         return (Socket) ret;
432     }
433
434     add234(sktree, ret);
435
436     return (Socket) ret;
437 }
438
439 Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
440               Plug plug)
441 {
442     static struct socket_function_table fn_table = {
443         sk_tcp_plug,
444         sk_tcp_close,
445         sk_tcp_write,
446         sk_tcp_write_oob,
447         sk_tcp_flush,
448         sk_tcp_socket_error
449     };
450
451     SOCKET s;
452 #ifdef IPV6
453     SOCKADDR_IN6 a6;
454 #endif
455     SOCKADDR_IN a;
456     DWORD err;
457     char *errstr;
458     Actual_Socket ret;
459     short localport;
460
461     /*
462      * Create Socket structure.
463      */
464     ret = smalloc(sizeof(struct Socket_tag));
465     ret->fn = &fn_table;
466     ret->error = NULL;
467     ret->plug = plug;
468     bufchain_init(&ret->output_data);
469     ret->connected = 0;                /* to start with */
470     ret->writable = 0;                 /* to start with */
471     ret->sending_oob = 0;
472     ret->frozen = 0;
473     ret->frozen_readable = 0;
474     ret->localhost_only = 0;           /* unused, but best init anyway */
475
476     /*
477      * Open socket.
478      */
479     s = socket(addr->family, SOCK_STREAM, 0);
480     ret->s = s;
481
482     if (s == INVALID_SOCKET) {
483         err = WSAGetLastError();
484         ret->error = winsock_error_string(err);
485         return (Socket) ret;
486     }
487
488     ret->oobinline = oobinline;
489     if (oobinline) {
490         BOOL b = TRUE;
491         setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b));
492     }
493
494     /*
495      * Bind to local address.
496      */
497     if (privport)
498         localport = 1023;              /* count from 1023 downwards */
499     else
500         localport = 0;                 /* just use port 0 (ie winsock picks) */
501
502     /* Loop round trying to bind */
503     while (1) {
504         int retcode;
505
506 #ifdef IPV6
507         if (addr->family == AF_INET6) {
508             memset(&a6, 0, sizeof(a6));
509             a6.sin6_family = AF_INET6;
510 /*a6.sin6_addr      = in6addr_any; *//* == 0 */
511             a6.sin6_port = htons(localport);
512         } else
513 #endif
514         {
515             a.sin_family = AF_INET;
516             a.sin_addr.s_addr = htonl(INADDR_ANY);
517             a.sin_port = htons(localport);
518         }
519 #ifdef IPV6
520         retcode = bind(s, (addr->family == AF_INET6 ?
521                            (struct sockaddr *) &a6 :
522                            (struct sockaddr *) &a),
523                        (addr->family ==
524                         AF_INET6 ? sizeof(a6) : sizeof(a)));
525 #else
526         retcode = bind(s, (struct sockaddr *) &a, sizeof(a));
527 #endif
528         if (retcode != SOCKET_ERROR) {
529             err = 0;
530             break;                     /* done */
531         } else {
532             err = WSAGetLastError();
533             if (err != WSAEADDRINUSE)  /* failed, for a bad reason */
534                 break;
535         }
536
537         if (localport == 0)
538             break;                     /* we're only looping once */
539         localport--;
540         if (localport == 0)
541             break;                     /* we might have got to the end */
542     }
543
544     if (err) {
545         ret->error = winsock_error_string(err);
546         return (Socket) ret;
547     }
548
549     /*
550      * Connect to remote address.
551      */
552 #ifdef IPV6
553     if (addr->family == AF_INET6) {
554         memset(&a, 0, sizeof(a));
555         a6.sin6_family = AF_INET6;
556         a6.sin6_port = htons((short) port);
557         a6.sin6_addr =
558             ((struct sockaddr_in6 *) addr->ai->ai_addr)->sin6_addr;
559     } else
560 #endif
561     {
562         a.sin_family = AF_INET;
563         a.sin_addr.s_addr = htonl(addr->address);
564         a.sin_port = htons((short) port);
565     }
566
567     /* Set up a select mechanism. This could be an AsyncSelect on a
568      * window, or an EventSelect on an event object. */
569     errstr = do_select(s, 1);
570     if (errstr) {
571         ret->error = errstr;
572         return (Socket) ret;
573     }
574
575     if ((
576 #ifdef IPV6
577             connect(s, ((addr->family == AF_INET6) ?
578                         (struct sockaddr *) &a6 : (struct sockaddr *) &a),
579                     (addr->family == AF_INET6) ? sizeof(a6) : sizeof(a))
580 #else
581             connect(s, (struct sockaddr *) &a, sizeof(a))
582 #endif
583         ) == SOCKET_ERROR) {
584         err = WSAGetLastError();
585         /*
586          * We expect a potential EWOULDBLOCK here, because the
587          * chances are the front end has done a select for
588          * FD_CONNECT, so that connect() will complete
589          * asynchronously.
590          */
591         if ( err != WSAEWOULDBLOCK ) {
592             ret->error = winsock_error_string(err);
593             return (Socket) ret;
594         }
595     } else {
596         /*
597          * If we _don't_ get EWOULDBLOCK, the connect has completed
598          * and we should set the socket as writable.
599          */
600         ret->writable = 1;
601     }
602
603     add234(sktree, ret);
604
605     return (Socket) ret;
606 }
607
608 Socket sk_newlistener(int port, Plug plug, int local_host_only)
609 {
610     static struct socket_function_table fn_table = {
611         sk_tcp_plug,
612         sk_tcp_close,
613         sk_tcp_write,
614         sk_tcp_write_oob,
615         sk_tcp_flush,
616         sk_tcp_socket_error
617     };
618
619     SOCKET s;
620 #ifdef IPV6
621     SOCKADDR_IN6 a6;
622 #endif
623     SOCKADDR_IN a;
624     DWORD err;
625     char *errstr;
626     Actual_Socket ret;
627     int retcode;
628     int on = 1;
629
630     /*
631      * Create Socket structure.
632      */
633     ret = smalloc(sizeof(struct Socket_tag));
634     ret->fn = &fn_table;
635     ret->error = NULL;
636     ret->plug = plug;
637     bufchain_init(&ret->output_data);
638     ret->writable = 0;                 /* to start with */
639     ret->sending_oob = 0;
640     ret->frozen = 0;
641     ret->frozen_readable = 0;
642     ret->localhost_only = local_host_only;
643
644     /*
645      * Open socket.
646      */
647     s = socket(AF_INET, SOCK_STREAM, 0);
648     ret->s = s;
649
650     if (s == INVALID_SOCKET) {
651         err = WSAGetLastError();
652         ret->error = winsock_error_string(err);
653         return (Socket) ret;
654     }
655
656     ret->oobinline = 0;
657
658
659     setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));
660
661
662 #ifdef IPV6
663         if (addr->family == AF_INET6) {
664             memset(&a6, 0, sizeof(a6));
665             a6.sin6_family = AF_INET6;
666             if (local_host_only)
667                 a6.sin6_addr = in6addr_loopback;
668             else
669                 a6.sin6_addr = in6addr_any;
670             a6.sin6_port = htons(port);
671         } else
672 #endif
673         {
674             a.sin_family = AF_INET;
675             if (local_host_only)
676                 a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
677             else
678                 a.sin_addr.s_addr = htonl(INADDR_ANY);
679             a.sin_port = htons((short)port);
680         }
681 #ifdef IPV6
682         retcode = bind(s, (addr->family == AF_INET6 ?
683                            (struct sockaddr *) &a6 :
684                            (struct sockaddr *) &a),
685                        (addr->family ==
686                         AF_INET6 ? sizeof(a6) : sizeof(a)));
687 #else
688         retcode = bind(s, (struct sockaddr *) &a, sizeof(a));
689 #endif
690         if (retcode != SOCKET_ERROR) {
691             err = 0;
692         } else {
693             err = WSAGetLastError();
694         }
695
696     if (err) {
697         ret->error = winsock_error_string(err);
698         return (Socket) ret;
699     }
700
701
702     if (listen(s, SOMAXCONN) == SOCKET_ERROR) {
703         closesocket(s);
704         ret->error = winsock_error_string(err);
705         return (Socket) ret;
706     }
707
708     /* Set up a select mechanism. This could be an AsyncSelect on a
709      * window, or an EventSelect on an event object. */
710     errstr = do_select(s, 1);
711     if (errstr) {
712         ret->error = errstr;
713         return (Socket) ret;
714     }
715
716     add234(sktree, ret);
717
718     return (Socket) ret;
719 }
720
721 static void sk_tcp_close(Socket sock)
722 {
723     extern char *do_select(SOCKET skt, int startup);
724     Actual_Socket s = (Actual_Socket) sock;
725
726     del234(sktree, s);
727     do_select(s->s, 0);
728     closesocket(s->s);
729     sfree(s);
730 }
731
732 /*
733  * The function which tries to send on a socket once it's deemed
734  * writable.
735  */
736 void try_send(Actual_Socket s)
737 {
738     while (s->sending_oob || bufchain_size(&s->output_data) > 0) {
739         int nsent;
740         DWORD err;
741         void *data;
742         int len, urgentflag;
743
744         if (s->sending_oob) {
745             urgentflag = MSG_OOB;
746             len = s->sending_oob;
747             data = &s->oobdata;
748         } else {
749             urgentflag = 0;
750             bufchain_prefix(&s->output_data, &data, &len);
751         }
752         nsent = send(s->s, data, len, urgentflag);
753         noise_ultralight(nsent);
754         if (nsent <= 0) {
755             err = (nsent < 0 ? WSAGetLastError() : 0);
756             if ((err < WSABASEERR && nsent < 0) || err == WSAEWOULDBLOCK) {
757                 /*
758                  * Perfectly normal: we've sent all we can for the moment.
759                  * 
760                  * (Some WinSock send() implementations can return
761                  * <0 but leave no sensible error indication -
762                  * WSAGetLastError() is called but returns zero or
763                  * a small number - so we check that case and treat
764                  * it just like WSAEWOULDBLOCK.)
765                  */
766                 s->writable = FALSE;
767                 return;
768             } else if (nsent == 0 ||
769                        err == WSAECONNABORTED || err == WSAECONNRESET) {
770                 /*
771                  * ASSUMPTION:
772                  * 
773                  * I'm assuming here that if a TCP connection is
774                  * reset or aborted once established, we will be
775                  * notified by a select event rather than a
776                  * CONNABORTED or CONNRESET from send(). In other
777                  * words, I'm assuming CONNABORTED and CONNRESET
778                  * don't come back from a _nonblocking_ send(),
779                  * because the local side doesn't know they've
780                  * happened until it waits for a response to its
781                  * TCP segment - so the error will arrive
782                  * asynchronously.
783                  * 
784                  * If I'm wrong, this will be a really nasty case,
785                  * because we can't necessarily call plug_closing()
786                  * without having to make half the SSH code
787                  * reentrant; so instead we'll have to schedule a
788                  * call to plug_closing() for some suitable future
789                  * time.
790                  */
791                 fatalbox("SERIOUS NETWORK INTERNAL ERROR: %s\n"
792                          "Please report this immediately to "
793                          "<putty@projects.tartarus.org>.",
794                          winsock_error_string(err));
795             } else {
796                 fatalbox(winsock_error_string(err));
797             }
798         } else {
799             if (s->sending_oob) {
800                 if (nsent < len) {
801                     memmove(s->oobdata, s->oobdata+nsent, len-nsent);
802                     s->sending_oob = len - nsent;
803                 } else {
804                     s->sending_oob = 0;
805                 }
806             } else {
807                 bufchain_consume(&s->output_data, nsent);
808             }
809         }
810     }
811 }
812
813 static int sk_tcp_write(Socket sock, char *buf, int len)
814 {
815     Actual_Socket s = (Actual_Socket) sock;
816
817     /*
818      * Add the data to the buffer list on the socket.
819      */
820     bufchain_add(&s->output_data, buf, len);
821
822     /*
823      * Now try sending from the start of the buffer list.
824      */
825     if (s->writable)
826         try_send(s);
827
828     return bufchain_size(&s->output_data);
829 }
830
831 static int sk_tcp_write_oob(Socket sock, char *buf, int len)
832 {
833     Actual_Socket s = (Actual_Socket) sock;
834
835     /*
836      * Replace the buffer list on the socket with the data.
837      */
838     bufchain_clear(&s->output_data);
839     assert(len <= sizeof(s->oobdata));
840     memcpy(s->oobdata, buf, len);
841     s->sending_oob = len;
842
843     /*
844      * Now try sending from the start of the buffer list.
845      */
846     if (s->writable)
847         try_send(s);
848
849     return s->sending_oob;
850 }
851
852 int select_result(WPARAM wParam, LPARAM lParam)
853 {
854     int ret, open;
855     DWORD err;
856     char buf[20480];                   /* nice big buffer for plenty of speed */
857     Actual_Socket s;
858     u_long atmark;
859
860     /* wParam is the socket itself */
861     s = find234(sktree, (void *) wParam, cmpforsearch);
862     if (!s)
863         return 1;                      /* boggle */
864
865     if ((err = WSAGETSELECTERROR(lParam)) != 0) {
866         /*
867          * An error has occurred on this socket. Pass it to the
868          * plug.
869          */
870         return plug_closing(s->plug, winsock_error_string(err), err, 0);
871     }
872
873     noise_ultralight(lParam);
874
875     switch (WSAGETSELECTEVENT(lParam)) {
876       case FD_CONNECT:
877         s->connected = s->writable = 1;
878         break;
879       case FD_READ:
880         /* In the case the socket is still frozen, we don't even bother */
881         if (s->frozen) {
882             s->frozen_readable = 1;
883             break;
884         }
885
886         /*
887          * We have received data on the socket. For an oobinline
888          * socket, this might be data _before_ an urgent pointer,
889          * in which case we send it to the back end with type==1
890          * (data prior to urgent).
891          */
892         if (s->oobinline) {
893             atmark = 1;
894             ioctlsocket(s->s, SIOCATMARK, &atmark);
895             /*
896              * Avoid checking the return value from ioctlsocket(),
897              * on the grounds that some WinSock wrappers don't
898              * support it. If it does nothing, we get atmark==1,
899              * which is equivalent to `no OOB pending', so the
900              * effect will be to non-OOB-ify any OOB data.
901              */
902         } else
903             atmark = 1;
904
905         ret = recv(s->s, buf, sizeof(buf), 0);
906         noise_ultralight(ret);
907         if (ret < 0) {
908             err = WSAGetLastError();
909             if (err == WSAEWOULDBLOCK) {
910                 break;
911             }
912         }
913         if (ret < 0) {
914             return plug_closing(s->plug, winsock_error_string(err), err,
915                                 0);
916         } else if (0 == ret) {
917             return plug_closing(s->plug, NULL, 0, 0);
918         } else {
919             return plug_receive(s->plug, atmark ? 0 : 1, buf, ret);
920         }
921         break;
922       case FD_OOB:
923         /*
924          * This will only happen on a non-oobinline socket. It
925          * indicates that we can immediately perform an OOB read
926          * and get back OOB data, which we will send to the back
927          * end with type==2 (urgent data).
928          */
929         ret = recv(s->s, buf, sizeof(buf), MSG_OOB);
930         noise_ultralight(ret);
931         if (ret <= 0) {
932             fatalbox(ret == 0 ? "Internal networking trouble" :
933                      winsock_error_string(WSAGetLastError()));
934         } else {
935             return plug_receive(s->plug, 2, buf, ret);
936         }
937         break;
938       case FD_WRITE:
939         {
940             int bufsize_before, bufsize_after;
941             s->writable = 1;
942             bufsize_before = s->sending_oob + bufchain_size(&s->output_data);
943             try_send(s);
944             bufsize_after = s->sending_oob + bufchain_size(&s->output_data);
945             if (bufsize_after < bufsize_before)
946                 plug_sent(s->plug, bufsize_after);
947         }
948         break;
949       case FD_CLOSE:
950         /* Signal a close on the socket. First read any outstanding data. */
951         open = 1;
952         do {
953             ret = recv(s->s, buf, sizeof(buf), 0);
954             if (ret < 0) {
955                 err = WSAGetLastError();
956                 if (err == WSAEWOULDBLOCK)
957                     break;
958                 return plug_closing(s->plug, winsock_error_string(err),
959                                     err, 0);
960             } else {
961                 if (ret)
962                     open &= plug_receive(s->plug, 0, buf, ret);
963                 else
964                     open &= plug_closing(s->plug, NULL, 0, 0);
965             }
966         } while (ret > 0);
967         return open;
968        case FD_ACCEPT:
969         {
970             struct sockaddr_in isa;
971             int addrlen = sizeof(struct sockaddr_in);
972             SOCKET t;  /* socket of connection */
973
974             memset(&isa, 0, sizeof(struct sockaddr_in));
975             err = 0;
976             t = accept(s->s,&isa,&addrlen);
977             if (t == INVALID_SOCKET)
978             {
979                 err = WSAGetLastError();
980                 if (err == WSATRY_AGAIN)
981                     break;
982             }
983
984             if (s->localhost_only &&
985                 ntohl(isa.sin_addr.s_addr) != INADDR_LOOPBACK) {
986                 closesocket(t);        /* dodgy WinSock let nonlocal through */
987             } else if (plug_accepting(s->plug, (void*)t)) {
988                 closesocket(t);        /* denied or error */
989             }
990         }
991     }
992
993     return 1;
994 }
995
996 /*
997  * Each socket abstraction contains a `void *' private field in
998  * which the client can keep state.
999  */
1000 void sk_set_private_ptr(Socket sock, void *ptr)
1001 {
1002     Actual_Socket s = (Actual_Socket) sock;
1003     s->private_ptr = ptr;
1004 }
1005
1006 void *sk_get_private_ptr(Socket sock)
1007 {
1008     Actual_Socket s = (Actual_Socket) sock;
1009     return s->private_ptr;
1010 }
1011
1012 /*
1013  * Special error values are returned from sk_namelookup and sk_new
1014  * if there's a problem. These functions extract an error message,
1015  * or return NULL if there's no problem.
1016  */
1017 char *sk_addr_error(SockAddr addr)
1018 {
1019     return addr->error;
1020 }
1021 static char *sk_tcp_socket_error(Socket sock)
1022 {
1023     Actual_Socket s = (Actual_Socket) sock;
1024     return s->error;
1025 }
1026
1027 void sk_set_frozen(Socket sock, int is_frozen)
1028 {
1029     Actual_Socket s = (Actual_Socket) sock;
1030     if (s->frozen == is_frozen)
1031         return;
1032     s->frozen = is_frozen;
1033     if (!is_frozen && s->frozen_readable) {
1034         char c;
1035         recv(s->s, &c, 1, MSG_PEEK);
1036     }
1037     s->frozen_readable = 0;
1038 }
1039
1040 /*
1041  * For Plink: enumerate all sockets currently active.
1042  */
1043 SOCKET first_socket(int *state)
1044 {
1045     Actual_Socket s;
1046     *state = 0;
1047     s = index234(sktree, (*state)++);
1048     return s ? s->s : INVALID_SOCKET;
1049 }
1050
1051 SOCKET next_socket(int *state)
1052 {
1053     Actual_Socket s = index234(sktree, (*state)++);
1054     return s ? s->s : INVALID_SOCKET;
1055 }