]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - windows/winnet.c
49306982b4761eae750487f0791a6d1eec49e6c2
[PuTTY.git] / windows / winnet.c
1 /*
2  * Windows networking abstraction.
3  *
4  * For the IPv6 code in here I am indebted to Jeroen Massar and
5  * unfix.org.
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <assert.h>
11
12 #define DEFINE_PLUG_METHOD_MACROS
13 #include "putty.h"
14 #include "network.h"
15 #include "tree234.h"
16
17 #include <ws2tcpip.h>
18
19 #ifndef NO_IPV6
20 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
21 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
22 #endif
23
24 #define ipv4_is_loopback(addr) \
25         ((p_ntohl(addr.s_addr) & 0xFF000000L) == 0x7F000000L)
26
27 struct Socket_tag {
28     const struct socket_function_table *fn;
29     /* the above variable absolutely *must* be the first in this structure */
30     char *error;
31     SOCKET s;
32     Plug plug;
33     void *private_ptr;
34     bufchain output_data;
35     int connected;
36     int writable;
37     int frozen; /* this causes readability notifications to be ignored */
38     int frozen_readable; /* this means we missed at least one readability
39                           * notification while we were frozen */
40     int localhost_only;                /* for listening sockets */
41     char oobdata[1];
42     int sending_oob;
43     int oobinline;
44     int pending_error;                 /* in case send() returns error */
45 };
46
47 /*
48  * We used to typedef struct Socket_tag *Socket.
49  *
50  * Since we have made the networking abstraction slightly more
51  * abstract, Socket no longer means a tcp socket (it could mean
52  * an ssl socket).  So now we must use Actual_Socket when we know
53  * we are talking about a tcp socket.
54  */
55 typedef struct Socket_tag *Actual_Socket;
56
57 struct SockAddr_tag {
58     char *error;
59     /* 
60      * Which address family this address belongs to. AF_INET for
61      * IPv4; AF_INET6 for IPv6; AF_UNSPEC indicates that name
62      * resolution has not been done and a simple host name is held
63      * in this SockAddr structure.
64      * The hostname field is also used when the hostname has both
65      * an IPv6 and IPv4 address and the IPv6 connection attempt
66      * fails. We then try the IPv4 address.
67      * This 'family' should become an option in the GUI and
68      * on the commandline for selecting a default protocol.
69      */
70     int family;
71     unsigned long address;             /* Address IPv4 style. */
72 #ifndef NO_IPV6
73     struct addrinfo *ai;               /* Address AF-independent (IPv4+IPv6) style. */
74 #endif
75     char hostname[512];                /* Store an unresolved host name. */
76 };
77
78 static tree234 *sktree;
79
80 static int cmpfortree(void *av, void *bv)
81 {
82     Actual_Socket a = (Actual_Socket) av, b = (Actual_Socket) bv;
83     unsigned long as = (unsigned long) a->s, bs = (unsigned long) b->s;
84     if (as < bs)
85         return -1;
86     if (as > bs)
87         return +1;
88     return 0;
89 }
90
91 static int cmpforsearch(void *av, void *bv)
92 {
93     Actual_Socket b = (Actual_Socket) bv;
94     unsigned long as = (unsigned long) av, bs = (unsigned long) b->s;
95     if (as < bs)
96         return -1;
97     if (as > bs)
98         return +1;
99     return 0;
100 }
101
102 #define NOTHING
103 #define DECL_WINSOCK_FUNCTION(linkage, rettype, name, params) \
104     typedef rettype (WINAPI *t_##name) params; \
105     linkage t_##name p_##name
106 #define GET_WINSOCK_FUNCTION(name) \
107     p_##name = (t_##name) GetProcAddress(winsock_module, #name)
108
109 DECL_WINSOCK_FUNCTION(NOTHING, int, WSAAsyncSelect,
110                       (SOCKET, HWND, u_int, long));
111 DECL_WINSOCK_FUNCTION(NOTHING, int, WSAEventSelect, (SOCKET, WSAEVENT, long));
112 DECL_WINSOCK_FUNCTION(NOTHING, int, select,
113                       (int, fd_set FAR *, fd_set FAR *,
114                        fd_set FAR *, const struct timeval FAR *));
115 DECL_WINSOCK_FUNCTION(NOTHING, int, WSAGetLastError, (void));
116 DECL_WINSOCK_FUNCTION(NOTHING, int, WSAEnumNetworkEvents,
117                       (SOCKET, WSAEVENT, LPWSANETWORKEVENTS));
118 DECL_WINSOCK_FUNCTION(static, int, WSAStartup, (WORD, LPWSADATA));
119 DECL_WINSOCK_FUNCTION(static, int, WSACleanup, (void));
120 DECL_WINSOCK_FUNCTION(static, int, closesocket, (SOCKET));
121 DECL_WINSOCK_FUNCTION(static, u_long, ntohl, (u_long));
122 DECL_WINSOCK_FUNCTION(static, u_long, htonl, (u_long));
123 DECL_WINSOCK_FUNCTION(static, u_short, htons, (u_short));
124 DECL_WINSOCK_FUNCTION(static, u_short, ntohs, (u_short));
125 DECL_WINSOCK_FUNCTION(static, struct hostent FAR *, gethostbyname,
126                       (const char FAR *));
127 DECL_WINSOCK_FUNCTION(static, struct servent FAR *, getservbyname,
128                       (const char FAR *, const char FAR *));
129 DECL_WINSOCK_FUNCTION(static, unsigned long, inet_addr, (const char FAR *));
130 DECL_WINSOCK_FUNCTION(static, char FAR *, inet_ntoa, (struct in_addr));
131 DECL_WINSOCK_FUNCTION(static, int, connect,
132                       (SOCKET, const struct sockaddr FAR *, int));
133 DECL_WINSOCK_FUNCTION(static, int, bind,
134                       (SOCKET, const struct sockaddr FAR *, int));
135 DECL_WINSOCK_FUNCTION(static, int, setsockopt,
136                       (SOCKET, int, int, const char FAR *, int));
137 DECL_WINSOCK_FUNCTION(static, SOCKET, socket, (int, int, int));
138 DECL_WINSOCK_FUNCTION(static, int, listen, (SOCKET, int));
139 DECL_WINSOCK_FUNCTION(static, int, send, (SOCKET, const char FAR *, int, int));
140 DECL_WINSOCK_FUNCTION(static, int, ioctlsocket,
141                       (SOCKET, long, u_long FAR *));
142 DECL_WINSOCK_FUNCTION(static, SOCKET, accept,
143                       (SOCKET, struct sockaddr FAR *, int FAR *));
144 DECL_WINSOCK_FUNCTION(static, int, recv, (SOCKET, char FAR *, int, int));
145 DECL_WINSOCK_FUNCTION(static, int, WSAIoctl,
146                       (SOCKET, DWORD, LPVOID, DWORD, LPVOID, DWORD,
147                        LPDWORD, LPWSAOVERLAPPED,
148                        LPWSAOVERLAPPED_COMPLETION_ROUTINE));
149
150 static HMODULE winsock_module;
151
152 void sk_init(void)
153 {
154     WORD winsock_ver;
155     WSADATA wsadata;
156
157     winsock_ver = MAKEWORD(2, 0);
158     winsock_module = LoadLibrary("WS2_32.DLL");
159     if (!winsock_module) {
160         winsock_module = LoadLibrary("WSOCK32.DLL");
161         winsock_ver = MAKEWORD(1, 1);
162     }
163     if (!winsock_module)
164         fatalbox("Unable to load any WinSock library");
165
166     GET_WINSOCK_FUNCTION(WSAAsyncSelect);
167     GET_WINSOCK_FUNCTION(WSAEventSelect);
168     GET_WINSOCK_FUNCTION(select);
169     GET_WINSOCK_FUNCTION(WSAGetLastError);
170     GET_WINSOCK_FUNCTION(WSAEnumNetworkEvents);
171     GET_WINSOCK_FUNCTION(WSAStartup);
172     GET_WINSOCK_FUNCTION(WSACleanup);
173     GET_WINSOCK_FUNCTION(closesocket);
174     GET_WINSOCK_FUNCTION(ntohl);
175     GET_WINSOCK_FUNCTION(htonl);
176     GET_WINSOCK_FUNCTION(htons);
177     GET_WINSOCK_FUNCTION(ntohs);
178     GET_WINSOCK_FUNCTION(gethostbyname);
179     GET_WINSOCK_FUNCTION(getservbyname);
180     GET_WINSOCK_FUNCTION(inet_addr);
181     GET_WINSOCK_FUNCTION(inet_ntoa);
182     GET_WINSOCK_FUNCTION(connect);
183     GET_WINSOCK_FUNCTION(bind);
184     GET_WINSOCK_FUNCTION(setsockopt);
185     GET_WINSOCK_FUNCTION(socket);
186     GET_WINSOCK_FUNCTION(listen);
187     GET_WINSOCK_FUNCTION(send);
188     GET_WINSOCK_FUNCTION(ioctlsocket);
189     GET_WINSOCK_FUNCTION(accept);
190     GET_WINSOCK_FUNCTION(recv);
191     GET_WINSOCK_FUNCTION(WSAIoctl);
192
193     if (p_WSAStartup(winsock_ver, &wsadata)) {
194         fatalbox("Unable to initialise WinSock");
195     }
196     if (LOBYTE(wsadata.wVersion) != LOBYTE(winsock_ver)) {
197         p_WSACleanup();
198         fatalbox("WinSock version is incompatible with %d.%d",
199                  LOBYTE(winsock_ver), HIBYTE(winsock_ver));
200     }
201
202     sktree = newtree234(cmpfortree);
203 }
204
205 void sk_cleanup(void)
206 {
207     Actual_Socket s;
208     int i;
209
210     if (sktree) {
211         for (i = 0; (s = index234(sktree, i)) != NULL; i++) {
212             p_closesocket(s->s);
213         }
214         freetree234(sktree);
215         sktree = NULL;
216     }
217
218     p_WSACleanup();
219     if (winsock_module)
220         FreeLibrary(winsock_module);
221 }
222
223 char *winsock_error_string(int error)
224 {
225     switch (error) {
226       case WSAEACCES:
227         return "Network error: Permission denied";
228       case WSAEADDRINUSE:
229         return "Network error: Address already in use";
230       case WSAEADDRNOTAVAIL:
231         return "Network error: Cannot assign requested address";
232       case WSAEAFNOSUPPORT:
233         return
234             "Network error: Address family not supported by protocol family";
235       case WSAEALREADY:
236         return "Network error: Operation already in progress";
237       case WSAECONNABORTED:
238         return "Network error: Software caused connection abort";
239       case WSAECONNREFUSED:
240         return "Network error: Connection refused";
241       case WSAECONNRESET:
242         return "Network error: Connection reset by peer";
243       case WSAEDESTADDRREQ:
244         return "Network error: Destination address required";
245       case WSAEFAULT:
246         return "Network error: Bad address";
247       case WSAEHOSTDOWN:
248         return "Network error: Host is down";
249       case WSAEHOSTUNREACH:
250         return "Network error: No route to host";
251       case WSAEINPROGRESS:
252         return "Network error: Operation now in progress";
253       case WSAEINTR:
254         return "Network error: Interrupted function call";
255       case WSAEINVAL:
256         return "Network error: Invalid argument";
257       case WSAEISCONN:
258         return "Network error: Socket is already connected";
259       case WSAEMFILE:
260         return "Network error: Too many open files";
261       case WSAEMSGSIZE:
262         return "Network error: Message too long";
263       case WSAENETDOWN:
264         return "Network error: Network is down";
265       case WSAENETRESET:
266         return "Network error: Network dropped connection on reset";
267       case WSAENETUNREACH:
268         return "Network error: Network is unreachable";
269       case WSAENOBUFS:
270         return "Network error: No buffer space available";
271       case WSAENOPROTOOPT:
272         return "Network error: Bad protocol option";
273       case WSAENOTCONN:
274         return "Network error: Socket is not connected";
275       case WSAENOTSOCK:
276         return "Network error: Socket operation on non-socket";
277       case WSAEOPNOTSUPP:
278         return "Network error: Operation not supported";
279       case WSAEPFNOSUPPORT:
280         return "Network error: Protocol family not supported";
281       case WSAEPROCLIM:
282         return "Network error: Too many processes";
283       case WSAEPROTONOSUPPORT:
284         return "Network error: Protocol not supported";
285       case WSAEPROTOTYPE:
286         return "Network error: Protocol wrong type for socket";
287       case WSAESHUTDOWN:
288         return "Network error: Cannot send after socket shutdown";
289       case WSAESOCKTNOSUPPORT:
290         return "Network error: Socket type not supported";
291       case WSAETIMEDOUT:
292         return "Network error: Connection timed out";
293       case WSAEWOULDBLOCK:
294         return "Network error: Resource temporarily unavailable";
295       case WSAEDISCON:
296         return "Network error: Graceful shutdown in progress";
297       default:
298         return "Unknown network error";
299     }
300 }
301
302 SockAddr sk_namelookup(const char *host, char **canonicalname,
303                        int address_family)
304 {
305     SockAddr ret = snew(struct SockAddr_tag);
306     unsigned long a;
307     struct hostent *h = NULL;
308     char realhost[8192];
309     int ret_family;
310     int err;
311
312     /* Clear the structure and default to IPv4. */
313     memset(ret, 0, sizeof(struct SockAddr_tag));
314     ret->family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
315 #ifndef NO_IPV6
316                    address_family == ADDRTYPE_IPV6 ? AF_INET6 :
317 #endif
318                    AF_UNSPEC);
319     ret_family = AF_UNSPEC;
320     *realhost = '\0';
321
322     if ((a = p_inet_addr(host)) == (unsigned long) INADDR_NONE) {
323 #ifndef NO_IPV6
324
325         /* Try to get the getaddrinfo() function from wship6.dll */
326         /* This way one doesn't need to have IPv6 dll's to use PuTTY and
327          * it will fallback to IPv4. */
328         typedef int (CALLBACK * FGETADDRINFO) (const char *nodename,
329                                                const char *servname,
330                                                const struct addrinfo *hints,
331                                                struct addrinfo **res);
332         FGETADDRINFO fGetAddrInfo = NULL;
333
334         HINSTANCE dllWSHIP6 = LoadLibrary("wship6.dll");
335         if (dllWSHIP6)
336             fGetAddrInfo = (FGETADDRINFO) GetProcAddress(dllWSHIP6,
337                                                          "getaddrinfo");
338
339         /*
340          * Use fGetAddrInfo when it's available
341          */
342         if (fGetAddrInfo) {
343             struct addrinfo hints;
344             memset(&hints, 0, sizeof(hints));
345             hints.ai_family = ret->family;
346             if ((err = fGetAddrInfo(host, NULL, &hints, &ret->ai)) == 0)
347                 ret_family = ret->ai->ai_family;
348         } else
349 #endif
350         {
351             /*
352              * Otherwise use the IPv4-only gethostbyname...
353              * (NOTE: we don't use gethostbyname as a fallback!)
354              */
355             if ( (h = p_gethostbyname(host)) )
356                 ret_family = AF_INET;
357             else
358                 err = p_WSAGetLastError();
359         }
360
361         if (ret_family == AF_UNSPEC) {
362             ret->error = (err == WSAENETDOWN ? "Network is down" :
363                           err == WSAHOST_NOT_FOUND ? "Host does not exist" :
364                           err == WSATRY_AGAIN ? "Host not found" :
365 #ifndef NO_IPV6
366                           fGetAddrInfo ? "getaddrinfo: unknown error" :
367 #endif
368                           "gethostbyname: unknown error");
369         } else {
370             ret->error = NULL;
371             ret->family = ret_family;
372
373 #ifndef NO_IPV6
374             /* If we got an address info use that... */
375             if (ret->ai) {
376                 typedef int (CALLBACK * FGETNAMEINFO)
377                  (const struct sockaddr FAR * sa, socklen_t salen,
378                   char FAR * host, size_t hostlen, char FAR * serv,
379                   size_t servlen, int flags);
380                 FGETNAMEINFO fGetNameInfo = NULL;
381
382                 /* Are we in IPv4 fallback mode? */
383                 /* We put the IPv4 address into the a variable so we can further-on use the IPv4 code... */
384                 if (ret->family == AF_INET)
385                     memcpy(&a,
386                            (char *) &((SOCKADDR_IN *) ret->ai->
387                                       ai_addr)->sin_addr, sizeof(a));
388
389                 /* Now let's find that canonicalname... */
390                 if ((dllWSHIP6)
391                     && (fGetNameInfo =
392                         (FGETNAMEINFO) GetProcAddress(dllWSHIP6,
393                                                       "getnameinfo"))) {
394                     if (fGetNameInfo
395                         ((struct sockaddr *) ret->ai->ai_addr,
396                          ret->family ==
397                          AF_INET ? sizeof(SOCKADDR_IN) :
398                          sizeof(SOCKADDR_IN6), realhost,
399                          sizeof(realhost), NULL, 0, 0) != 0) {
400                         strncpy(realhost, host, sizeof(realhost));
401                     }
402                 }
403             }
404             /* We used the IPv4-only gethostbyname()... */
405             else
406 #endif
407             {
408                 memcpy(&a, h->h_addr, sizeof(a));
409                 /* This way we are always sure the h->h_name is valid :) */
410                 strncpy(realhost, h->h_name, sizeof(realhost));
411             }
412         }
413 #ifndef NO_IPV6
414         FreeLibrary(dllWSHIP6);
415 #endif
416     } else {
417         /*
418          * This must be a numeric IPv4 address because it caused a
419          * success return from inet_addr.
420          */
421         ret->family = AF_INET;
422         strncpy(realhost, host, sizeof(realhost));
423     }
424     ret->address = p_ntohl(a);
425     realhost[lenof(realhost)-1] = '\0';
426     *canonicalname = snewn(1+strlen(realhost), char);
427     strcpy(*canonicalname, realhost);
428     return ret;
429 }
430
431 SockAddr sk_nonamelookup(const char *host)
432 {
433     SockAddr ret = snew(struct SockAddr_tag);
434     ret->error = NULL;
435     ret->family = AF_UNSPEC;
436     strncpy(ret->hostname, host, lenof(ret->hostname));
437     ret->hostname[lenof(ret->hostname)-1] = '\0';
438     return ret;
439 }
440
441 void sk_getaddr(SockAddr addr, char *buf, int buflen)
442 {
443 #ifndef NO_IPV6
444     if (addr->family == AF_INET6) {
445         /* Try to get the WSAAddressToStringA() function from wship6.dll */
446         /* This way one doesn't need to have IPv6 dll's to use PuTTY and
447          * it will fallback to IPv4. */
448         typedef int (CALLBACK * FADDRTOSTR) (LPSOCKADDR lpsaAddress,
449                 DWORD dwAddressLength,
450                 LPWSAPROTOCOL_INFO lpProtocolInfo,
451                 OUT LPTSTR lpszAddressString,
452                 IN OUT LPDWORD lpdwAddressStringLength
453         );
454         FADDRTOSTR fAddrToStr = NULL;
455
456         HINSTANCE dllWS2 = LoadLibrary("ws2_32.dll");
457         if (dllWS2) {
458             fAddrToStr = (FADDRTOSTR)GetProcAddress(dllWS2,
459                                                     "WSAAddressToStringA");
460             if (fAddrToStr) {
461                 fAddrToStr(addr->ai->ai_addr, addr->ai->ai_addrlen,
462                            NULL, buf, &buflen);
463             }
464             else strncpy(buf, "IPv6", buflen);
465             FreeLibrary(dllWS2);
466         }
467     } else
468 #endif
469     if (addr->family == AF_INET) {
470         struct in_addr a;
471         a.s_addr = p_htonl(addr->address);
472         strncpy(buf, p_inet_ntoa(a), buflen);
473         buf[buflen-1] = '\0';
474     } else {
475         strncpy(buf, addr->hostname, buflen);
476         buf[buflen-1] = '\0';
477     }
478 }
479
480 int sk_hostname_is_local(char *name)
481 {
482     return !strcmp(name, "localhost");
483 }
484
485 static INTERFACE_INFO local_interfaces[16];
486 static int n_local_interfaces;       /* 0=not yet, -1=failed, >0=number */
487
488 static int ipv4_is_local_addr(struct in_addr addr)
489 {
490     if (ipv4_is_loopback(addr))
491         return 1;                      /* loopback addresses are local */
492     if (!n_local_interfaces) {
493         SOCKET s = p_socket(AF_INET, SOCK_DGRAM, 0);
494         DWORD retbytes;
495
496         if (p_WSAIoctl &&
497             p_WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0,
498                        local_interfaces, sizeof(local_interfaces),
499                        &retbytes, NULL, NULL) == 0)
500             n_local_interfaces = retbytes / sizeof(INTERFACE_INFO);
501         else
502             logevent(NULL, "Unable to get list of local IP addresses");
503     }
504     if (n_local_interfaces > 0) {
505         int i;
506         for (i = 0; i < n_local_interfaces; i++) {
507             SOCKADDR_IN *address =
508                 (SOCKADDR_IN *)&local_interfaces[i].iiAddress;
509             if (address->sin_addr.s_addr == addr.s_addr)
510                 return 1;              /* this address is local */
511         }
512     }
513     return 0;                  /* this address is not local */
514 }
515
516 int sk_address_is_local(SockAddr addr)
517 {
518 #ifndef NO_IPV6
519     if (addr->family == AF_INET6) {
520         return IN6_IS_ADDR_LOOPBACK((const struct in6_addr *)addr->ai->ai_addr);
521     } else
522 #endif
523     if (addr->family == AF_INET) {
524         struct in_addr a;
525         a.s_addr = p_htonl(addr->address);
526         return ipv4_is_local_addr(a);
527     } else {
528         assert(addr->family == AF_UNSPEC);
529         return 0;                      /* we don't know; assume not */
530     }
531 }
532
533 int sk_addrtype(SockAddr addr)
534 {
535     return (addr->family == AF_INET ? ADDRTYPE_IPV4 :
536 #ifndef NO_IPV6
537             addr->family == AF_INET6 ? ADDRTYPE_IPV6 :
538 #endif
539             ADDRTYPE_NAME);
540 }
541
542 void sk_addrcopy(SockAddr addr, char *buf)
543 {
544     assert(addr->family != AF_UNSPEC);
545 #ifndef NO_IPV6
546     if (addr->family == AF_INET6) {
547         memcpy(buf, (char*) addr->ai, 16);
548     } else
549 #endif
550     if (addr->family == AF_INET) {
551         struct in_addr a;
552         a.s_addr = p_htonl(addr->address);
553         memcpy(buf, (char*) &a.s_addr, 4);
554     }
555 }
556
557 void sk_addr_free(SockAddr addr)
558 {
559     sfree(addr);
560 }
561
562 static Plug sk_tcp_plug(Socket sock, Plug p)
563 {
564     Actual_Socket s = (Actual_Socket) sock;
565     Plug ret = s->plug;
566     if (p)
567         s->plug = p;
568     return ret;
569 }
570
571 static void sk_tcp_flush(Socket s)
572 {
573     /*
574      * We send data to the socket as soon as we can anyway,
575      * so we don't need to do anything here.  :-)
576      */
577 }
578
579 static void sk_tcp_close(Socket s);
580 static int sk_tcp_write(Socket s, const char *data, int len);
581 static int sk_tcp_write_oob(Socket s, const char *data, int len);
582 static void sk_tcp_set_private_ptr(Socket s, void *ptr);
583 static void *sk_tcp_get_private_ptr(Socket s);
584 static void sk_tcp_set_frozen(Socket s, int is_frozen);
585 static const char *sk_tcp_socket_error(Socket s);
586
587 extern char *do_select(SOCKET skt, int startup);
588
589 Socket sk_register(void *sock, Plug plug)
590 {
591     static const struct socket_function_table fn_table = {
592         sk_tcp_plug,
593         sk_tcp_close,
594         sk_tcp_write,
595         sk_tcp_write_oob,
596         sk_tcp_flush,
597         sk_tcp_set_private_ptr,
598         sk_tcp_get_private_ptr,
599         sk_tcp_set_frozen,
600         sk_tcp_socket_error
601     };
602
603     DWORD err;
604     char *errstr;
605     Actual_Socket ret;
606
607     /*
608      * Create Socket structure.
609      */
610     ret = snew(struct Socket_tag);
611     ret->fn = &fn_table;
612     ret->error = NULL;
613     ret->plug = plug;
614     bufchain_init(&ret->output_data);
615     ret->writable = 1;                 /* to start with */
616     ret->sending_oob = 0;
617     ret->frozen = 1;
618     ret->frozen_readable = 0;
619     ret->localhost_only = 0;           /* unused, but best init anyway */
620     ret->pending_error = 0;
621
622     ret->s = (SOCKET)sock;
623
624     if (ret->s == INVALID_SOCKET) {
625         err = p_WSAGetLastError();
626         ret->error = winsock_error_string(err);
627         return (Socket) ret;
628     }
629
630     ret->oobinline = 0;
631
632     /* Set up a select mechanism. This could be an AsyncSelect on a
633      * window, or an EventSelect on an event object. */
634     errstr = do_select(ret->s, 1);
635     if (errstr) {
636         ret->error = errstr;
637         return (Socket) ret;
638     }
639
640     add234(sktree, ret);
641
642     return (Socket) ret;
643 }
644
645 Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
646               int nodelay, int keepalive, Plug plug)
647 {
648     static const struct socket_function_table fn_table = {
649         sk_tcp_plug,
650         sk_tcp_close,
651         sk_tcp_write,
652         sk_tcp_write_oob,
653         sk_tcp_flush,
654         sk_tcp_set_private_ptr,
655         sk_tcp_get_private_ptr,
656         sk_tcp_set_frozen,
657         sk_tcp_socket_error
658     };
659
660     SOCKET s;
661 #ifndef NO_IPV6
662     SOCKADDR_IN6 a6;
663 #endif
664     SOCKADDR_IN a;
665     DWORD err;
666     char *errstr;
667     Actual_Socket ret;
668     short localport;
669
670     /*
671      * Create Socket structure.
672      */
673     ret = snew(struct Socket_tag);
674     ret->fn = &fn_table;
675     ret->error = NULL;
676     ret->plug = plug;
677     bufchain_init(&ret->output_data);
678     ret->connected = 0;                /* to start with */
679     ret->writable = 0;                 /* to start with */
680     ret->sending_oob = 0;
681     ret->frozen = 0;
682     ret->frozen_readable = 0;
683     ret->localhost_only = 0;           /* unused, but best init anyway */
684     ret->pending_error = 0;
685
686     /*
687      * Open socket.
688      */
689 #ifndef NO_IPV6
690     /* Let's default to IPv6, this shouldn't hurt anybody
691      * If the stack supports IPv6 it will also allow IPv4 connections. */
692     if (addr->family == AF_UNSPEC) addr->family = AF_INET6;
693 #else
694     /* No other choice, default to IPv4 */
695     if (addr->family == AF_UNSPEC) addr->family = AF_INET;
696 #endif
697     s = p_socket(addr->family, SOCK_STREAM, 0);
698     ret->s = s;
699
700     if (s == INVALID_SOCKET) {
701         err = p_WSAGetLastError();
702         ret->error = winsock_error_string(err);
703         return (Socket) ret;
704     }
705
706     ret->oobinline = oobinline;
707     if (oobinline) {
708         BOOL b = TRUE;
709         p_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b));
710     }
711
712     if (nodelay) {
713         BOOL b = TRUE;
714         p_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b));
715     }
716
717     if (keepalive) {
718         BOOL b = TRUE;
719         p_setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b));
720     }
721
722     /*
723      * Bind to local address.
724      */
725     if (privport)
726         localport = 1023;              /* count from 1023 downwards */
727     else
728         localport = 0;                 /* just use port 0 (ie winsock picks) */
729
730     /* Loop round trying to bind */
731     while (1) {
732         int retcode;
733
734 #ifndef NO_IPV6
735         if (addr->family == AF_INET6) {
736             memset(&a6, 0, sizeof(a6));
737             a6.sin6_family = AF_INET6;
738           /*a6.sin6_addr = in6addr_any; */ /* == 0 done by memset() */
739             a6.sin6_port = p_htons(localport);
740         } else
741 #endif
742         {
743             a.sin_family = AF_INET;
744             a.sin_addr.s_addr = p_htonl(INADDR_ANY);
745             a.sin_port = p_htons(localport);
746         }
747 #ifndef NO_IPV6
748         retcode = p_bind(s, (addr->family == AF_INET6 ?
749                            (struct sockaddr *) &a6 :
750                            (struct sockaddr *) &a),
751                        (addr->family ==
752                         AF_INET6 ? sizeof(a6) : sizeof(a)));
753 #else
754         retcode = p_bind(s, (struct sockaddr *) &a, sizeof(a));
755 #endif
756         if (retcode != SOCKET_ERROR) {
757             err = 0;
758             break;                     /* done */
759         } else {
760             err = p_WSAGetLastError();
761             if (err != WSAEADDRINUSE)  /* failed, for a bad reason */
762                 break;
763         }
764
765         if (localport == 0)
766             break;                     /* we're only looping once */
767         localport--;
768         if (localport == 0)
769             break;                     /* we might have got to the end */
770     }
771
772     if (err) {
773         ret->error = winsock_error_string(err);
774         return (Socket) ret;
775     }
776
777     /*
778      * Connect to remote address.
779      */
780 #ifndef NO_IPV6
781     if (addr->family == AF_INET6) {
782         memset(&a, 0, sizeof(a));
783         a6.sin6_family = AF_INET6;
784         a6.sin6_port = p_htons((short) port);
785         a6.sin6_addr =
786             ((struct sockaddr_in6 *) addr->ai->ai_addr)->sin6_addr;
787     } else
788 #endif
789     {
790         a.sin_family = AF_INET;
791         a.sin_addr.s_addr = p_htonl(addr->address);
792         a.sin_port = p_htons((short) port);
793     }
794
795     /* Set up a select mechanism. This could be an AsyncSelect on a
796      * window, or an EventSelect on an event object. */
797     errstr = do_select(s, 1);
798     if (errstr) {
799         ret->error = errstr;
800         return (Socket) ret;
801     }
802
803     if ((
804 #ifndef NO_IPV6
805             p_connect(s, ((addr->family == AF_INET6) ?
806                         (struct sockaddr *) &a6 : (struct sockaddr *) &a),
807                     (addr->family == AF_INET6) ? sizeof(a6) : sizeof(a))
808 #else
809             p_connect(s, (struct sockaddr *) &a, sizeof(a))
810 #endif
811         ) == SOCKET_ERROR) {
812         err = p_WSAGetLastError();
813         /*
814          * We expect a potential EWOULDBLOCK here, because the
815          * chances are the front end has done a select for
816          * FD_CONNECT, so that connect() will complete
817          * asynchronously.
818          */
819         if ( err != WSAEWOULDBLOCK ) {
820             ret->error = winsock_error_string(err);
821             return (Socket) ret;
822         }
823     } else {
824         /*
825          * If we _don't_ get EWOULDBLOCK, the connect has completed
826          * and we should set the socket as writable.
827          */
828         ret->writable = 1;
829     }
830
831     add234(sktree, ret);
832
833     /* We're done with 'addr' now. */
834     sk_addr_free(addr);
835
836     return (Socket) ret;
837 }
838
839 Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,
840                       int address_family)
841 {
842     static const struct socket_function_table fn_table = {
843         sk_tcp_plug,
844         sk_tcp_close,
845         sk_tcp_write,
846         sk_tcp_write_oob,
847         sk_tcp_flush,
848         sk_tcp_set_private_ptr,
849         sk_tcp_get_private_ptr,
850         sk_tcp_set_frozen,
851         sk_tcp_socket_error
852     };
853
854     SOCKET s;
855 #ifndef NO_IPV6
856     SOCKADDR_IN6 a6;
857 #endif
858     SOCKADDR_IN a;
859
860     DWORD err;
861     char *errstr;
862     Actual_Socket ret;
863     int retcode;
864     int on = 1;
865
866     /*
867      * Create Socket structure.
868      */
869     ret = snew(struct Socket_tag);
870     ret->fn = &fn_table;
871     ret->error = NULL;
872     ret->plug = plug;
873     bufchain_init(&ret->output_data);
874     ret->writable = 0;                 /* to start with */
875     ret->sending_oob = 0;
876     ret->frozen = 0;
877     ret->frozen_readable = 0;
878     ret->localhost_only = local_host_only;
879     ret->pending_error = 0;
880
881     /*
882      * Translate address_family from platform-independent constants
883      * into local reality.
884      */
885     address_family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
886 #ifndef NO_IPV6
887                       address_family == ADDRTYPE_IPV6 ? AF_INET6 :
888 #endif
889                       AF_UNSPEC);
890  
891 #ifndef NO_IPV6
892     /* Let's default to IPv6, this shouldn't hurt anybody
893      * If the stack supports IPv6 it will also allow IPv4 connections. */
894     if (address_family == AF_UNSPEC) address_family = AF_INET6;
895 #else
896     /* No other choice, default to IPv4 */
897     if (address_family == AF_UNSPEC)  address_family = AF_INET;
898 #endif
899
900     /*
901      * Open socket.
902      */
903     s = p_socket(address_family, SOCK_STREAM, 0);
904     ret->s = s;
905
906     if (s == INVALID_SOCKET) {
907         err = p_WSAGetLastError();
908         ret->error = winsock_error_string(err);
909         return (Socket) ret;
910     }
911
912     ret->oobinline = 0;
913
914     p_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));
915
916 #ifndef NO_IPV6
917         if (address_family == AF_INET6) {
918             memset(&a6, 0, sizeof(a6));
919             a6.sin6_family = AF_INET6;
920             /* FIXME: srcaddr is ignored for IPv6, because I (SGT) don't
921              * know how to do it. :-)
922              * (jeroen:) saddr is specified as an address.. eg 2001:db8::1
923              * Thus we need either a parser that understands [2001:db8::1]:80
924              * style addresses and/or enhance this to understand hostnames too. */
925             if (local_host_only)
926                 a6.sin6_addr = in6addr_loopback;
927             else
928                 a6.sin6_addr = in6addr_any;
929             a6.sin6_port = p_htons(port);
930         } else
931 #endif
932         {
933             int got_addr = 0;
934             a.sin_family = AF_INET;
935
936             /*
937              * Bind to source address. First try an explicitly
938              * specified one...
939              */
940             if (srcaddr) {
941                 a.sin_addr.s_addr = p_inet_addr(srcaddr);
942                 if (a.sin_addr.s_addr != INADDR_NONE) {
943                     /* Override localhost_only with specified listen addr. */
944                     ret->localhost_only = ipv4_is_loopback(a.sin_addr);
945                     got_addr = 1;
946                 }
947             }
948
949             /*
950              * ... and failing that, go with one of the standard ones.
951              */
952             if (!got_addr) {
953                 if (local_host_only)
954                     a.sin_addr.s_addr = p_htonl(INADDR_LOOPBACK);
955                 else
956                     a.sin_addr.s_addr = p_htonl(INADDR_ANY);
957             }
958
959             a.sin_port = p_htons((short)port);
960         }
961 #ifndef NO_IPV6
962         retcode = p_bind(s, (address_family == AF_INET6 ?
963                            (struct sockaddr *) &a6 :
964                            (struct sockaddr *) &a),
965                        (address_family ==
966                         AF_INET6 ? sizeof(a6) : sizeof(a)));
967 #else
968         retcode = p_bind(s, (struct sockaddr *) &a, sizeof(a));
969 #endif
970         if (retcode != SOCKET_ERROR) {
971             err = 0;
972         } else {
973             err = p_WSAGetLastError();
974         }
975
976     if (err) {
977         ret->error = winsock_error_string(err);
978         return (Socket) ret;
979     }
980
981
982     if (p_listen(s, SOMAXCONN) == SOCKET_ERROR) {
983         p_closesocket(s);
984         ret->error = winsock_error_string(err);
985         return (Socket) ret;
986     }
987
988     /* Set up a select mechanism. This could be an AsyncSelect on a
989      * window, or an EventSelect on an event object. */
990     errstr = do_select(s, 1);
991     if (errstr) {
992         ret->error = errstr;
993         return (Socket) ret;
994     }
995
996     add234(sktree, ret);
997
998     return (Socket) ret;
999 }
1000
1001 static void sk_tcp_close(Socket sock)
1002 {
1003     extern char *do_select(SOCKET skt, int startup);
1004     Actual_Socket s = (Actual_Socket) sock;
1005
1006     del234(sktree, s);
1007     do_select(s->s, 0);
1008     p_closesocket(s->s);
1009     sfree(s);
1010 }
1011
1012 /*
1013  * The function which tries to send on a socket once it's deemed
1014  * writable.
1015  */
1016 void try_send(Actual_Socket s)
1017 {
1018     while (s->sending_oob || bufchain_size(&s->output_data) > 0) {
1019         int nsent;
1020         DWORD err;
1021         void *data;
1022         int len, urgentflag;
1023
1024         if (s->sending_oob) {
1025             urgentflag = MSG_OOB;
1026             len = s->sending_oob;
1027             data = &s->oobdata;
1028         } else {
1029             urgentflag = 0;
1030             bufchain_prefix(&s->output_data, &data, &len);
1031         }
1032         nsent = p_send(s->s, data, len, urgentflag);
1033         noise_ultralight(nsent);
1034         if (nsent <= 0) {
1035             err = (nsent < 0 ? p_WSAGetLastError() : 0);
1036             if ((err < WSABASEERR && nsent < 0) || err == WSAEWOULDBLOCK) {
1037                 /*
1038                  * Perfectly normal: we've sent all we can for the moment.
1039                  * 
1040                  * (Some WinSock send() implementations can return
1041                  * <0 but leave no sensible error indication -
1042                  * WSAGetLastError() is called but returns zero or
1043                  * a small number - so we check that case and treat
1044                  * it just like WSAEWOULDBLOCK.)
1045                  */
1046                 s->writable = FALSE;
1047                 return;
1048             } else if (nsent == 0 ||
1049                        err == WSAECONNABORTED || err == WSAECONNRESET) {
1050                 /*
1051                  * If send() returns CONNABORTED or CONNRESET, we
1052                  * unfortunately can't just call plug_closing(),
1053                  * because it's quite likely that we're currently
1054                  * _in_ a call from the code we'd be calling back
1055                  * to, so we'd have to make half the SSH code
1056                  * reentrant. Instead we flag a pending error on
1057                  * the socket, to be dealt with (by calling
1058                  * plug_closing()) at some suitable future moment.
1059                  */
1060                 s->pending_error = err;
1061                 return;
1062             } else {
1063                 /* We're inside the Windows frontend here, so we know
1064                  * that the frontend handle is unnecessary. */
1065                 logevent(NULL, winsock_error_string(err));
1066                 fatalbox("%s", winsock_error_string(err));
1067             }
1068         } else {
1069             if (s->sending_oob) {
1070                 if (nsent < len) {
1071                     memmove(s->oobdata, s->oobdata+nsent, len-nsent);
1072                     s->sending_oob = len - nsent;
1073                 } else {
1074                     s->sending_oob = 0;
1075                 }
1076             } else {
1077                 bufchain_consume(&s->output_data, nsent);
1078             }
1079         }
1080     }
1081 }
1082
1083 static int sk_tcp_write(Socket sock, const char *buf, int len)
1084 {
1085     Actual_Socket s = (Actual_Socket) sock;
1086
1087     /*
1088      * Add the data to the buffer list on the socket.
1089      */
1090     bufchain_add(&s->output_data, buf, len);
1091
1092     /*
1093      * Now try sending from the start of the buffer list.
1094      */
1095     if (s->writable)
1096         try_send(s);
1097
1098     return bufchain_size(&s->output_data);
1099 }
1100
1101 static int sk_tcp_write_oob(Socket sock, const char *buf, int len)
1102 {
1103     Actual_Socket s = (Actual_Socket) sock;
1104
1105     /*
1106      * Replace the buffer list on the socket with the data.
1107      */
1108     bufchain_clear(&s->output_data);
1109     assert(len <= sizeof(s->oobdata));
1110     memcpy(s->oobdata, buf, len);
1111     s->sending_oob = len;
1112
1113     /*
1114      * Now try sending from the start of the buffer list.
1115      */
1116     if (s->writable)
1117         try_send(s);
1118
1119     return s->sending_oob;
1120 }
1121
1122 int select_result(WPARAM wParam, LPARAM lParam)
1123 {
1124     int ret, open;
1125     DWORD err;
1126     char buf[20480];                   /* nice big buffer for plenty of speed */
1127     Actual_Socket s;
1128     u_long atmark;
1129
1130     /* wParam is the socket itself */
1131
1132     if (wParam == 0)
1133         return 1;                      /* boggle */
1134
1135     s = find234(sktree, (void *) wParam, cmpforsearch);
1136     if (!s)
1137         return 1;                      /* boggle */
1138
1139     if ((err = WSAGETSELECTERROR(lParam)) != 0) {
1140         /*
1141          * An error has occurred on this socket. Pass it to the
1142          * plug.
1143          */
1144         return plug_closing(s->plug, winsock_error_string(err), err, 0);
1145     }
1146
1147     noise_ultralight(lParam);
1148
1149     switch (WSAGETSELECTEVENT(lParam)) {
1150       case FD_CONNECT:
1151         s->connected = s->writable = 1;
1152         break;
1153       case FD_READ:
1154         /* In the case the socket is still frozen, we don't even bother */
1155         if (s->frozen) {
1156             s->frozen_readable = 1;
1157             break;
1158         }
1159
1160         /*
1161          * We have received data on the socket. For an oobinline
1162          * socket, this might be data _before_ an urgent pointer,
1163          * in which case we send it to the back end with type==1
1164          * (data prior to urgent).
1165          */
1166         if (s->oobinline) {
1167             atmark = 1;
1168             p_ioctlsocket(s->s, SIOCATMARK, &atmark);
1169             /*
1170              * Avoid checking the return value from ioctlsocket(),
1171              * on the grounds that some WinSock wrappers don't
1172              * support it. If it does nothing, we get atmark==1,
1173              * which is equivalent to `no OOB pending', so the
1174              * effect will be to non-OOB-ify any OOB data.
1175              */
1176         } else
1177             atmark = 1;
1178
1179         ret = p_recv(s->s, buf, sizeof(buf), 0);
1180         noise_ultralight(ret);
1181         if (ret < 0) {
1182             err = p_WSAGetLastError();
1183             if (err == WSAEWOULDBLOCK) {
1184                 break;
1185             }
1186         }
1187         if (ret < 0) {
1188             return plug_closing(s->plug, winsock_error_string(err), err,
1189                                 0);
1190         } else if (0 == ret) {
1191             return plug_closing(s->plug, NULL, 0, 0);
1192         } else {
1193             return plug_receive(s->plug, atmark ? 0 : 1, buf, ret);
1194         }
1195         break;
1196       case FD_OOB:
1197         /*
1198          * This will only happen on a non-oobinline socket. It
1199          * indicates that we can immediately perform an OOB read
1200          * and get back OOB data, which we will send to the back
1201          * end with type==2 (urgent data).
1202          */
1203         ret = p_recv(s->s, buf, sizeof(buf), MSG_OOB);
1204         noise_ultralight(ret);
1205         if (ret <= 0) {
1206             char *str = (ret == 0 ? "Internal networking trouble" :
1207                          winsock_error_string(p_WSAGetLastError()));
1208             /* We're inside the Windows frontend here, so we know
1209              * that the frontend handle is unnecessary. */
1210             logevent(NULL, str);
1211             fatalbox("%s", str);
1212         } else {
1213             return plug_receive(s->plug, 2, buf, ret);
1214         }
1215         break;
1216       case FD_WRITE:
1217         {
1218             int bufsize_before, bufsize_after;
1219             s->writable = 1;
1220             bufsize_before = s->sending_oob + bufchain_size(&s->output_data);
1221             try_send(s);
1222             bufsize_after = s->sending_oob + bufchain_size(&s->output_data);
1223             if (bufsize_after < bufsize_before)
1224                 plug_sent(s->plug, bufsize_after);
1225         }
1226         break;
1227       case FD_CLOSE:
1228         /* Signal a close on the socket. First read any outstanding data. */
1229         open = 1;
1230         do {
1231             ret = p_recv(s->s, buf, sizeof(buf), 0);
1232             if (ret < 0) {
1233                 err = p_WSAGetLastError();
1234                 if (err == WSAEWOULDBLOCK)
1235                     break;
1236                 return plug_closing(s->plug, winsock_error_string(err),
1237                                     err, 0);
1238             } else {
1239                 if (ret)
1240                     open &= plug_receive(s->plug, 0, buf, ret);
1241                 else
1242                     open &= plug_closing(s->plug, NULL, 0, 0);
1243             }
1244         } while (ret > 0);
1245         return open;
1246        case FD_ACCEPT:
1247         {
1248 #ifdef NO_IPV6
1249             struct sockaddr_in isa;
1250 #else
1251             struct sockaddr_storage isa;
1252 #endif
1253             int addrlen = sizeof(isa);
1254             SOCKET t;  /* socket of connection */
1255
1256             memset(&isa, 0, sizeof(isa));
1257             err = 0;
1258             t = p_accept(s->s,(struct sockaddr *)&isa,&addrlen);
1259             if (t == INVALID_SOCKET)
1260             {
1261                 err = p_WSAGetLastError();
1262                 if (err == WSATRY_AGAIN)
1263                     break;
1264             }
1265 #ifndef NO_IPV6
1266             if (isa.ss_family == AF_INET &&
1267                 s->localhost_only &&
1268                 !ipv4_is_local_addr(((struct sockaddr_in *)&isa)->sin_addr)) {
1269 #else
1270             if (s->localhost_only && !ipv4_is_local_addr(isa.sin_addr)) {
1271 #endif
1272                 p_closesocket(t);      /* dodgy WinSock let nonlocal through */
1273             } else if (plug_accepting(s->plug, (void*)t)) {
1274                 p_closesocket(t);      /* denied or error */
1275             }
1276         }
1277     }
1278
1279     return 1;
1280 }
1281
1282 /*
1283  * Deal with socket errors detected in try_send().
1284  */
1285 void net_pending_errors(void)
1286 {
1287     int i;
1288     Actual_Socket s;
1289
1290     /*
1291      * This might be a fiddly business, because it's just possible
1292      * that handling a pending error on one socket might cause
1293      * others to be closed. (I can't think of any reason this might
1294      * happen in current SSH implementation, but to maintain
1295      * generality of this network layer I'll assume the worst.)
1296      * 
1297      * So what we'll do is search the socket list for _one_ socket
1298      * with a pending error, and then handle it, and then search
1299      * the list again _from the beginning_. Repeat until we make a
1300      * pass with no socket errors present. That way we are
1301      * protected against the socket list changing under our feet.
1302      */
1303
1304     do {
1305         for (i = 0; (s = index234(sktree, i)) != NULL; i++) {
1306             if (s->pending_error) {
1307                 /*
1308                  * An error has occurred on this socket. Pass it to the
1309                  * plug.
1310                  */
1311                 plug_closing(s->plug,
1312                              winsock_error_string(s->pending_error),
1313                              s->pending_error, 0);
1314                 break;
1315             }
1316         }
1317     } while (s);
1318 }
1319
1320 /*
1321  * Each socket abstraction contains a `void *' private field in
1322  * which the client can keep state.
1323  */
1324 static void sk_tcp_set_private_ptr(Socket sock, void *ptr)
1325 {
1326     Actual_Socket s = (Actual_Socket) sock;
1327     s->private_ptr = ptr;
1328 }
1329
1330 static void *sk_tcp_get_private_ptr(Socket sock)
1331 {
1332     Actual_Socket s = (Actual_Socket) sock;
1333     return s->private_ptr;
1334 }
1335
1336 /*
1337  * Special error values are returned from sk_namelookup and sk_new
1338  * if there's a problem. These functions extract an error message,
1339  * or return NULL if there's no problem.
1340  */
1341 const char *sk_addr_error(SockAddr addr)
1342 {
1343     return addr->error;
1344 }
1345 static const char *sk_tcp_socket_error(Socket sock)
1346 {
1347     Actual_Socket s = (Actual_Socket) sock;
1348     return s->error;
1349 }
1350
1351 static void sk_tcp_set_frozen(Socket sock, int is_frozen)
1352 {
1353     Actual_Socket s = (Actual_Socket) sock;
1354     if (s->frozen == is_frozen)
1355         return;
1356     s->frozen = is_frozen;
1357     if (!is_frozen && s->frozen_readable) {
1358         char c;
1359         p_recv(s->s, &c, 1, MSG_PEEK);
1360     }
1361     s->frozen_readable = 0;
1362 }
1363
1364 /*
1365  * For Plink: enumerate all sockets currently active.
1366  */
1367 SOCKET first_socket(int *state)
1368 {
1369     Actual_Socket s;
1370     *state = 0;
1371     s = index234(sktree, (*state)++);
1372     return s ? s->s : INVALID_SOCKET;
1373 }
1374
1375 SOCKET next_socket(int *state)
1376 {
1377     Actual_Socket s = index234(sktree, (*state)++);
1378     return s ? s->s : INVALID_SOCKET;
1379 }
1380
1381 extern int socket_writable(SOCKET skt)
1382 {
1383     Actual_Socket s = find234(sktree, (void *)skt, cmpforsearch);
1384
1385     if (s)
1386         return bufchain_size(&s->output_data) > 0;
1387     else
1388         return 0;
1389 }
1390
1391 int net_service_lookup(char *service)
1392 {
1393     struct servent *se;
1394     se = p_getservbyname(service, NULL);
1395     if (se != NULL)
1396         return p_ntohs(se->s_port);
1397     else
1398         return 0;
1399 }
1400
1401 SockAddr platform_get_x11_unix_address(int displaynum, char **canonicalname)
1402 {
1403     SockAddr ret = snew(struct SockAddr_tag);
1404     memset(ret, 0, sizeof(struct SockAddr_tag));
1405     ret->error = "unix sockets not supported on this platform";
1406     return ret;
1407 }