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