Fix some possible resource leaks
[TortoiseGit.git] / src / TortoisePlink / Windows / WINNET.C
blob60e77edfede165c601046d5335a0a018c1317476
1 /*\r
2  * Windows networking abstraction.\r
3  *\r
4  * For the IPv6 code in here I am indebted to Jeroen Massar and\r
5  * unfix.org.\r
6  */\r
7 \r
8 #include <stdio.h>\r
9 #include <stdlib.h>\r
10 #include <assert.h>\r
12 #define DEFINE_PLUG_METHOD_MACROS\r
13 #include "putty.h"\r
14 #include "network.h"\r
15 #include "tree234.h"\r
17 #include <ws2tcpip.h>\r
19 #ifndef NO_IPV6\r
20 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;\r
21 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;\r
22 #endif\r
24 #define ipv4_is_loopback(addr) \\r
25         ((p_ntohl(addr.s_addr) & 0xFF000000L) == 0x7F000000L)\r
27 /*\r
28  * We used to typedef struct Socket_tag *Socket.\r
29  *\r
30  * Since we have made the networking abstraction slightly more\r
31  * abstract, Socket no longer means a tcp socket (it could mean\r
32  * an ssl socket).  So now we must use Actual_Socket when we know\r
33  * we are talking about a tcp socket.\r
34  */\r
35 typedef struct Socket_tag *Actual_Socket;\r
37 /*\r
38  * Mutable state that goes with a SockAddr: stores information\r
39  * about where in the list of candidate IP(v*) addresses we've\r
40  * currently got to.\r
41  */\r
42 typedef struct SockAddrStep_tag SockAddrStep;\r
43 struct SockAddrStep_tag {\r
44 #ifndef NO_IPV6\r
45     struct addrinfo *ai;               /* steps along addr->ais */\r
46 #endif\r
47     int curraddr;\r
48 };\r
50 struct Socket_tag {\r
51     const struct socket_function_table *fn;\r
52     /* the above variable absolutely *must* be the first in this structure */\r
53     char *error;\r
54     SOCKET s;\r
55     Plug plug;\r
56     void *private_ptr;\r
57     bufchain output_data;\r
58     int connected;\r
59     int writable;\r
60     int frozen; /* this causes readability notifications to be ignored */\r
61     int frozen_readable; /* this means we missed at least one readability\r
62                           * notification while we were frozen */\r
63     int localhost_only;                /* for listening sockets */\r
64     char oobdata[1];\r
65     int sending_oob;\r
66     int oobinline, nodelay, keepalive, privport;\r
67     enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof;\r
68     SockAddr addr;\r
69     SockAddrStep step;\r
70     int port;\r
71     int pending_error;                 /* in case send() returns error */\r
72     /*\r
73      * We sometimes need pairs of Socket structures to be linked:\r
74      * if we are listening on the same IPv6 and v4 port, for\r
75      * example. So here we define `parent' and `child' pointers to\r
76      * track this link.\r
77      */\r
78     Actual_Socket parent, child;\r
79 };\r
81 struct SockAddr_tag {\r
82     int refcount;\r
83     char *error;\r
84     int resolved;\r
85 #ifndef NO_IPV6\r
86     struct addrinfo *ais;              /* Addresses IPv6 style. */\r
87 #endif\r
88     unsigned long *addresses;          /* Addresses IPv4 style. */\r
89     int naddresses;\r
90     char hostname[512];                /* Store an unresolved host name. */\r
91 };\r
93 /*\r
94  * Which address family this address belongs to. AF_INET for IPv4;\r
95  * AF_INET6 for IPv6; AF_UNSPEC indicates that name resolution has\r
96  * not been done and a simple host name is held in this SockAddr\r
97  * structure.\r
98  */\r
99 #ifndef NO_IPV6\r
100 #define SOCKADDR_FAMILY(addr, step) \\r
101     (!(addr)->resolved ? AF_UNSPEC : \\r
102      (step).ai ? (step).ai->ai_family : AF_INET)\r
103 #else\r
104 #define SOCKADDR_FAMILY(addr, step) \\r
105     (!(addr)->resolved ? AF_UNSPEC : AF_INET)\r
106 #endif\r
108 /*\r
109  * Start a SockAddrStep structure to step through multiple\r
110  * addresses.\r
111  */\r
112 #ifndef NO_IPV6\r
113 #define START_STEP(addr, step) \\r
114     ((step).ai = (addr)->ais, (step).curraddr = 0)\r
115 #else\r
116 #define START_STEP(addr, step) \\r
117     ((step).curraddr = 0)\r
118 #endif\r
120 static tree234 *sktree;\r
122 static int cmpfortree(void *av, void *bv)\r
124     Actual_Socket a = (Actual_Socket) av, b = (Actual_Socket) bv;\r
125     unsigned long as = (unsigned long) a->s, bs = (unsigned long) b->s;\r
126     if (as < bs)\r
127         return -1;\r
128     if (as > bs)\r
129         return +1;\r
130     if (a < b)\r
131         return -1;\r
132     if (a > b)\r
133         return +1;\r
134     return 0;\r
137 static int cmpforsearch(void *av, void *bv)\r
139     Actual_Socket b = (Actual_Socket) bv;\r
140     unsigned long as = (unsigned long) av, bs = (unsigned long) b->s;\r
141     if (as < bs)\r
142         return -1;\r
143     if (as > bs)\r
144         return +1;\r
145     return 0;\r
148 DECL_WINDOWS_FUNCTION(static, int, WSAStartup, (WORD, LPWSADATA));\r
149 DECL_WINDOWS_FUNCTION(static, int, WSACleanup, (void));\r
150 DECL_WINDOWS_FUNCTION(static, int, closesocket, (SOCKET));\r
151 DECL_WINDOWS_FUNCTION(static, u_long, ntohl, (u_long));\r
152 DECL_WINDOWS_FUNCTION(static, u_long, htonl, (u_long));\r
153 DECL_WINDOWS_FUNCTION(static, u_short, htons, (u_short));\r
154 DECL_WINDOWS_FUNCTION(static, u_short, ntohs, (u_short));\r
155 DECL_WINDOWS_FUNCTION(static, int, gethostname, (char *, int));\r
156 DECL_WINDOWS_FUNCTION(static, struct hostent FAR *, gethostbyname,\r
157                       (const char FAR *));\r
158 DECL_WINDOWS_FUNCTION(static, struct servent FAR *, getservbyname,\r
159                       (const char FAR *, const char FAR *));\r
160 DECL_WINDOWS_FUNCTION(static, unsigned long, inet_addr, (const char FAR *));\r
161 DECL_WINDOWS_FUNCTION(static, char FAR *, inet_ntoa, (struct in_addr));\r
162 DECL_WINDOWS_FUNCTION(static, int, connect,\r
163                       (SOCKET, const struct sockaddr FAR *, int));\r
164 DECL_WINDOWS_FUNCTION(static, int, bind,\r
165                       (SOCKET, const struct sockaddr FAR *, int));\r
166 DECL_WINDOWS_FUNCTION(static, int, setsockopt,\r
167                       (SOCKET, int, int, const char FAR *, int));\r
168 DECL_WINDOWS_FUNCTION(static, SOCKET, socket, (int, int, int));\r
169 DECL_WINDOWS_FUNCTION(static, int, listen, (SOCKET, int));\r
170 DECL_WINDOWS_FUNCTION(static, int, send, (SOCKET, const char FAR *, int, int));\r
171 DECL_WINDOWS_FUNCTION(static, int, shutdown, (SOCKET, int));\r
172 DECL_WINDOWS_FUNCTION(static, int, ioctlsocket,\r
173                       (SOCKET, long, u_long FAR *));\r
174 DECL_WINDOWS_FUNCTION(static, SOCKET, accept,\r
175                       (SOCKET, struct sockaddr FAR *, int FAR *));\r
176 DECL_WINDOWS_FUNCTION(static, int, recv, (SOCKET, char FAR *, int, int));\r
177 DECL_WINDOWS_FUNCTION(static, int, WSAIoctl,\r
178                       (SOCKET, DWORD, LPVOID, DWORD, LPVOID, DWORD,\r
179                        LPDWORD, LPWSAOVERLAPPED,\r
180                        LPWSAOVERLAPPED_COMPLETION_ROUTINE));\r
181 #ifndef NO_IPV6\r
182 DECL_WINDOWS_FUNCTION(static, int, getaddrinfo,\r
183                       (const char *nodename, const char *servname,\r
184                        const struct addrinfo *hints, struct addrinfo **res));\r
185 DECL_WINDOWS_FUNCTION(static, void, freeaddrinfo, (struct addrinfo *res));\r
186 DECL_WINDOWS_FUNCTION(static, int, getnameinfo,\r
187                       (const struct sockaddr FAR * sa, socklen_t salen,\r
188                        char FAR * host, size_t hostlen, char FAR * serv,\r
189                        size_t servlen, int flags));\r
190 DECL_WINDOWS_FUNCTION(static, char *, gai_strerror, (int ecode));\r
191 DECL_WINDOWS_FUNCTION(static, int, WSAAddressToStringA,\r
192                       (LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFO,\r
193                        LPSTR, LPDWORD));\r
194 #endif\r
196 static HMODULE winsock_module = NULL;\r
197 static WSADATA wsadata;\r
198 #ifndef NO_IPV6\r
199 static HMODULE winsock2_module = NULL;\r
200 static HMODULE wship6_module = NULL;\r
201 #endif\r
203 int sk_startup(int hi, int lo)\r
205     WORD winsock_ver;\r
207     winsock_ver = MAKEWORD(hi, lo);\r
209     if (p_WSAStartup(winsock_ver, &wsadata)) {\r
210         return FALSE;\r
211     }\r
213     if (LOBYTE(wsadata.wVersion) != LOBYTE(winsock_ver)) {\r
214         return FALSE;\r
215     }\r
217 #ifdef NET_SETUP_DIAGNOSTICS\r
218     {\r
219         char buf[80];\r
220         sprintf(buf, "Using WinSock %d.%d", hi, lo);\r
221         logevent(NULL, buf);\r
222     }\r
223 #endif\r
224     return TRUE;\r
227 void sk_init(void)\r
229 #ifndef NO_IPV6\r
230     winsock2_module =\r
231 #endif\r
232         winsock_module = load_system32_dll("ws2_32.dll");\r
233     if (!winsock_module) {\r
234         winsock_module = load_system32_dll("wsock32.dll");\r
235     }\r
236     if (!winsock_module)\r
237         fatalbox("Unable to load any WinSock library");\r
239 #ifndef NO_IPV6\r
240     /* Check if we have getaddrinfo in Winsock */\r
241     if (GetProcAddress(winsock_module, "getaddrinfo") != NULL) {\r
242 #ifdef NET_SETUP_DIAGNOSTICS\r
243         logevent(NULL, "Native WinSock IPv6 support detected");\r
244 #endif\r
245         GET_WINDOWS_FUNCTION(winsock_module, getaddrinfo);\r
246         GET_WINDOWS_FUNCTION(winsock_module, freeaddrinfo);\r
247         GET_WINDOWS_FUNCTION(winsock_module, getnameinfo);\r
248         GET_WINDOWS_FUNCTION(winsock_module, gai_strerror);\r
249     } else {\r
250         /* Fall back to wship6.dll for Windows 2000 */\r
251         wship6_module = load_system32_dll("wship6.dll");\r
252         if (wship6_module) {\r
253 #ifdef NET_SETUP_DIAGNOSTICS\r
254             logevent(NULL, "WSH IPv6 support detected");\r
255 #endif\r
256             GET_WINDOWS_FUNCTION(wship6_module, getaddrinfo);\r
257             GET_WINDOWS_FUNCTION(wship6_module, freeaddrinfo);\r
258             GET_WINDOWS_FUNCTION(wship6_module, getnameinfo);\r
259             GET_WINDOWS_FUNCTION(wship6_module, gai_strerror);\r
260         } else {\r
261 #ifdef NET_SETUP_DIAGNOSTICS\r
262             logevent(NULL, "No IPv6 support detected");\r
263 #endif\r
264         }\r
265     }\r
266     GET_WINDOWS_FUNCTION(winsock2_module, WSAAddressToStringA);\r
267 #else\r
268 #ifdef NET_SETUP_DIAGNOSTICS\r
269     logevent(NULL, "PuTTY was built without IPv6 support");\r
270 #endif\r
271 #endif\r
273     GET_WINDOWS_FUNCTION(winsock_module, WSAAsyncSelect);\r
274     GET_WINDOWS_FUNCTION(winsock_module, WSAEventSelect);\r
275     GET_WINDOWS_FUNCTION(winsock_module, select);\r
276     GET_WINDOWS_FUNCTION(winsock_module, WSAGetLastError);\r
277     GET_WINDOWS_FUNCTION(winsock_module, WSAEnumNetworkEvents);\r
278     GET_WINDOWS_FUNCTION(winsock_module, WSAStartup);\r
279     GET_WINDOWS_FUNCTION(winsock_module, WSACleanup);\r
280     GET_WINDOWS_FUNCTION(winsock_module, closesocket);\r
281     GET_WINDOWS_FUNCTION(winsock_module, ntohl);\r
282     GET_WINDOWS_FUNCTION(winsock_module, htonl);\r
283     GET_WINDOWS_FUNCTION(winsock_module, htons);\r
284     GET_WINDOWS_FUNCTION(winsock_module, ntohs);\r
285     GET_WINDOWS_FUNCTION(winsock_module, gethostname);\r
286     GET_WINDOWS_FUNCTION(winsock_module, gethostbyname);\r
287     GET_WINDOWS_FUNCTION(winsock_module, getservbyname);\r
288     GET_WINDOWS_FUNCTION(winsock_module, inet_addr);\r
289     GET_WINDOWS_FUNCTION(winsock_module, inet_ntoa);\r
290     GET_WINDOWS_FUNCTION(winsock_module, connect);\r
291     GET_WINDOWS_FUNCTION(winsock_module, bind);\r
292     GET_WINDOWS_FUNCTION(winsock_module, setsockopt);\r
293     GET_WINDOWS_FUNCTION(winsock_module, socket);\r
294     GET_WINDOWS_FUNCTION(winsock_module, listen);\r
295     GET_WINDOWS_FUNCTION(winsock_module, send);\r
296     GET_WINDOWS_FUNCTION(winsock_module, shutdown);\r
297     GET_WINDOWS_FUNCTION(winsock_module, ioctlsocket);\r
298     GET_WINDOWS_FUNCTION(winsock_module, accept);\r
299     GET_WINDOWS_FUNCTION(winsock_module, recv);\r
300     GET_WINDOWS_FUNCTION(winsock_module, WSAIoctl);\r
302     /* Try to get the best WinSock version we can get */\r
303     if (!sk_startup(2,2) &&\r
304         !sk_startup(2,0) &&\r
305         !sk_startup(1,1)) {\r
306         fatalbox("Unable to initialise WinSock");\r
307     }\r
309     sktree = newtree234(cmpfortree);\r
312 void sk_cleanup(void)\r
314     Actual_Socket s;\r
315     int i;\r
317     if (sktree) {\r
318         for (i = 0; (s = index234(sktree, i)) != NULL; i++) {\r
319             p_closesocket(s->s);\r
320         }\r
321         freetree234(sktree);\r
322         sktree = NULL;\r
323     }\r
325     if (p_WSACleanup)\r
326         p_WSACleanup();\r
327     if (winsock_module)\r
328         FreeLibrary(winsock_module);\r
329 #ifndef NO_IPV6\r
330     if (wship6_module)\r
331         FreeLibrary(wship6_module);\r
332 #endif\r
335 struct errstring {\r
336     int error;\r
337     char *text;\r
338 };\r
340 static int errstring_find(void *av, void *bv)\r
342     int *a = (int *)av;\r
343     struct errstring *b = (struct errstring *)bv;\r
344     if (*a < b->error)\r
345         return -1;\r
346     if (*a > b->error)\r
347         return +1;\r
348     return 0;\r
350 static int errstring_compare(void *av, void *bv)\r
352     struct errstring *a = (struct errstring *)av;\r
353     return errstring_find(&a->error, bv);\r
356 static tree234 *errstrings = NULL;\r
358 char *winsock_error_string(int error)\r
360     const char prefix[] = "Network error: ";\r
361     struct errstring *es;\r
363     /*\r
364      * Error codes we know about and have historically had reasonably\r
365      * sensible error messages for.\r
366      */\r
367     switch (error) {\r
368       case WSAEACCES:\r
369         return "Network error: Permission denied";\r
370       case WSAEADDRINUSE:\r
371         return "Network error: Address already in use";\r
372       case WSAEADDRNOTAVAIL:\r
373         return "Network error: Cannot assign requested address";\r
374       case WSAEAFNOSUPPORT:\r
375         return\r
376             "Network error: Address family not supported by protocol family";\r
377       case WSAEALREADY:\r
378         return "Network error: Operation already in progress";\r
379       case WSAECONNABORTED:\r
380         return "Network error: Software caused connection abort";\r
381       case WSAECONNREFUSED:\r
382         return "Network error: Connection refused";\r
383       case WSAECONNRESET:\r
384         return "Network error: Connection reset by peer";\r
385       case WSAEDESTADDRREQ:\r
386         return "Network error: Destination address required";\r
387       case WSAEFAULT:\r
388         return "Network error: Bad address";\r
389       case WSAEHOSTDOWN:\r
390         return "Network error: Host is down";\r
391       case WSAEHOSTUNREACH:\r
392         return "Network error: No route to host";\r
393       case WSAEINPROGRESS:\r
394         return "Network error: Operation now in progress";\r
395       case WSAEINTR:\r
396         return "Network error: Interrupted function call";\r
397       case WSAEINVAL:\r
398         return "Network error: Invalid argument";\r
399       case WSAEISCONN:\r
400         return "Network error: Socket is already connected";\r
401       case WSAEMFILE:\r
402         return "Network error: Too many open files";\r
403       case WSAEMSGSIZE:\r
404         return "Network error: Message too long";\r
405       case WSAENETDOWN:\r
406         return "Network error: Network is down";\r
407       case WSAENETRESET:\r
408         return "Network error: Network dropped connection on reset";\r
409       case WSAENETUNREACH:\r
410         return "Network error: Network is unreachable";\r
411       case WSAENOBUFS:\r
412         return "Network error: No buffer space available";\r
413       case WSAENOPROTOOPT:\r
414         return "Network error: Bad protocol option";\r
415       case WSAENOTCONN:\r
416         return "Network error: Socket is not connected";\r
417       case WSAENOTSOCK:\r
418         return "Network error: Socket operation on non-socket";\r
419       case WSAEOPNOTSUPP:\r
420         return "Network error: Operation not supported";\r
421       case WSAEPFNOSUPPORT:\r
422         return "Network error: Protocol family not supported";\r
423       case WSAEPROCLIM:\r
424         return "Network error: Too many processes";\r
425       case WSAEPROTONOSUPPORT:\r
426         return "Network error: Protocol not supported";\r
427       case WSAEPROTOTYPE:\r
428         return "Network error: Protocol wrong type for socket";\r
429       case WSAESHUTDOWN:\r
430         return "Network error: Cannot send after socket shutdown";\r
431       case WSAESOCKTNOSUPPORT:\r
432         return "Network error: Socket type not supported";\r
433       case WSAETIMEDOUT:\r
434         return "Network error: Connection timed out";\r
435       case WSAEWOULDBLOCK:\r
436         return "Network error: Resource temporarily unavailable";\r
437       case WSAEDISCON:\r
438         return "Network error: Graceful shutdown in progress";\r
439     }\r
441     /*\r
442      * Generic code to handle any other error.\r
443      *\r
444      * Slightly nasty hack here: we want to return a static string\r
445      * which the caller will never have to worry about freeing, but on\r
446      * the other hand if we call FormatMessage to get it then it will\r
447      * want to either allocate a buffer or write into one we own.\r
448      *\r
449      * So what we do is to maintain a tree234 of error strings we've\r
450      * already used. New ones are allocated from the heap, but then\r
451      * put in this tree and kept forever.\r
452      */\r
454     if (!errstrings)\r
455         errstrings = newtree234(errstring_compare);\r
457     es = find234(errstrings, &error, errstring_find);\r
459     if (!es) {\r
460         int bufsize, bufused;\r
462         es = snew(struct errstring);\r
463         es->error = error;\r
464         /* maximum size for FormatMessage is 64K */\r
465         bufsize = 65535 + sizeof(prefix);\r
466         es->text = snewn(bufsize, char);\r
467         strcpy(es->text, prefix);\r
468         bufused = strlen(es->text);\r
469         if (!FormatMessage((FORMAT_MESSAGE_FROM_SYSTEM |\r
470                             FORMAT_MESSAGE_IGNORE_INSERTS), NULL, error,\r
471                            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
472                            es->text + bufused, bufsize - bufused, NULL)) {\r
473             sprintf(es->text + bufused,\r
474                     "Windows error code %d (and FormatMessage returned %d)", \r
475                     error, GetLastError());\r
476         } else {\r
477             int len = strlen(es->text);\r
478             if (len > 0 && es->text[len-1] == '\n')\r
479                 es->text[len-1] = '\0';\r
480         }\r
481         es->text = sresize(es->text, strlen(es->text) + 1, char);\r
482         add234(errstrings, es);\r
483     }\r
485     return es->text;\r
488 SockAddr sk_namelookup(const char *host, char **canonicalname,\r
489                        int address_family)\r
491     SockAddr ret = snew(struct SockAddr_tag);\r
492     unsigned long a;\r
493     char realhost[8192];\r
494     int hint_family;\r
496     /* Default to IPv4. */\r
497     hint_family = (address_family == ADDRTYPE_IPV4 ? AF_INET :\r
498 #ifndef NO_IPV6\r
499                    address_family == ADDRTYPE_IPV6 ? AF_INET6 :\r
500 #endif\r
501                    AF_UNSPEC);\r
503     /* Clear the structure and default to IPv4. */\r
504     memset(ret, 0, sizeof(struct SockAddr_tag));\r
505 #ifndef NO_IPV6\r
506     ret->ais = NULL;\r
507 #endif\r
508     ret->addresses = NULL;\r
509     ret->resolved = FALSE;\r
510     ret->refcount = 1;\r
511     *realhost = '\0';\r
513     if ((a = p_inet_addr(host)) == (unsigned long) INADDR_NONE) {\r
514         struct hostent *h = NULL;\r
515         int err;\r
516 #ifndef NO_IPV6\r
517         /*\r
518          * Use getaddrinfo when it's available\r
519          */\r
520         if (p_getaddrinfo) {\r
521             struct addrinfo hints;\r
522 #ifdef NET_SETUP_DIAGNOSTICS\r
523             logevent(NULL, "Using getaddrinfo() for resolving");\r
524 #endif\r
525             memset(&hints, 0, sizeof(hints));\r
526             hints.ai_family = hint_family;\r
527             hints.ai_flags = AI_CANONNAME;\r
528             if ((err = p_getaddrinfo(host, NULL, &hints, &ret->ais)) == 0)\r
529                 ret->resolved = TRUE;\r
530         } else\r
531 #endif\r
532         {\r
533 #ifdef NET_SETUP_DIAGNOSTICS\r
534             logevent(NULL, "Using gethostbyname() for resolving");\r
535 #endif\r
536             /*\r
537              * Otherwise use the IPv4-only gethostbyname...\r
538              * (NOTE: we don't use gethostbyname as a fallback!)\r
539              */\r
540             if ( (h = p_gethostbyname(host)) )\r
541                 ret->resolved = TRUE;\r
542             else\r
543                 err = p_WSAGetLastError();\r
544         }\r
546         if (!ret->resolved) {\r
547             ret->error = (err == WSAENETDOWN ? "Network is down" :\r
548                           err == WSAHOST_NOT_FOUND ? "Host does not exist" :\r
549                           err == WSATRY_AGAIN ? "Host not found" :\r
550 #ifndef NO_IPV6\r
551                           p_getaddrinfo&&p_gai_strerror ? p_gai_strerror(err) :\r
552 #endif\r
553                           "gethostbyname: unknown error");\r
554         } else {\r
555             ret->error = NULL;\r
557 #ifndef NO_IPV6\r
558             /* If we got an address info use that... */\r
559             if (ret->ais) {\r
560                 /* Are we in IPv4 fallback mode? */\r
561                 /* We put the IPv4 address into the a variable so we can further-on use the IPv4 code... */\r
562                 if (ret->ais->ai_family == AF_INET)\r
563                     memcpy(&a,\r
564                            (char *) &((SOCKADDR_IN *) ret->ais->\r
565                                       ai_addr)->sin_addr, sizeof(a));\r
567                 if (ret->ais->ai_canonname)\r
568                     strncpy(realhost, ret->ais->ai_canonname, lenof(realhost));\r
569                 else\r
570                     strncpy(realhost, host, lenof(realhost));\r
571             }\r
572             /* We used the IPv4-only gethostbyname()... */\r
573             else\r
574 #endif\r
575             {\r
576                 int n;\r
577                 for (n = 0; h->h_addr_list[n]; n++);\r
578                 ret->addresses = snewn(n, unsigned long);\r
579                 ret->naddresses = n;\r
580                 for (n = 0; n < ret->naddresses; n++) {\r
581                     memcpy(&a, h->h_addr_list[n], sizeof(a));\r
582                     ret->addresses[n] = p_ntohl(a);\r
583                 }\r
584                 memcpy(&a, h->h_addr, sizeof(a));\r
585                 /* This way we are always sure the h->h_name is valid :) */\r
586                 strncpy(realhost, h->h_name, sizeof(realhost));\r
587             }\r
588         }\r
589     } else {\r
590         /*\r
591          * This must be a numeric IPv4 address because it caused a\r
592          * success return from inet_addr.\r
593          */\r
594         ret->addresses = snewn(1, unsigned long);\r
595         ret->naddresses = 1;\r
596         ret->addresses[0] = p_ntohl(a);\r
597         ret->resolved = TRUE;\r
598         strncpy(realhost, host, sizeof(realhost));\r
599     }\r
600     realhost[lenof(realhost)-1] = '\0';\r
601     *canonicalname = snewn(1+strlen(realhost), char);\r
602     strcpy(*canonicalname, realhost);\r
603     return ret;\r
606 SockAddr sk_nonamelookup(const char *host)\r
608     SockAddr ret = snew(struct SockAddr_tag);\r
609     ret->error = NULL;\r
610     ret->resolved = FALSE;\r
611 #ifndef NO_IPV6\r
612     ret->ais = NULL;\r
613 #endif\r
614     ret->addresses = NULL;\r
615     ret->naddresses = 0;\r
616     ret->refcount = 1;\r
617     strncpy(ret->hostname, host, lenof(ret->hostname));\r
618     ret->hostname[lenof(ret->hostname)-1] = '\0';\r
619     return ret;\r
622 int sk_nextaddr(SockAddr addr, SockAddrStep *step)\r
624 #ifndef NO_IPV6\r
625     if (step->ai) {\r
626         if (step->ai->ai_next) {\r
627             step->ai = step->ai->ai_next;\r
628             return TRUE;\r
629         } else\r
630             return FALSE;\r
631     }\r
632 #endif\r
633     if (step->curraddr+1 < addr->naddresses) {\r
634         step->curraddr++;\r
635         return TRUE;\r
636     } else {\r
637         return FALSE;\r
638     }\r
641 void sk_getaddr(SockAddr addr, char *buf, int buflen)\r
643     SockAddrStep step;\r
644     START_STEP(addr, step);\r
646 #ifndef NO_IPV6\r
647     if (step.ai) {\r
648         int err = 0;\r
649         if (p_WSAAddressToStringA) {\r
650             DWORD dwbuflen = buflen;\r
651             err = p_WSAAddressToStringA(step.ai->ai_addr, step.ai->ai_addrlen,\r
652                                         NULL, buf, &dwbuflen);\r
653         } else\r
654             err = -1;\r
655         if (err) {\r
656             strncpy(buf, addr->hostname, buflen);\r
657             if (!buf[0])\r
658                 strncpy(buf, "<unknown>", buflen);\r
659             buf[buflen-1] = '\0';\r
660         }\r
661     } else\r
662 #endif\r
663     if (SOCKADDR_FAMILY(addr, step) == AF_INET) {\r
664         struct in_addr a;\r
665         assert(addr->addresses && step.curraddr < addr->naddresses);\r
666         a.s_addr = p_htonl(addr->addresses[step.curraddr]);\r
667         strncpy(buf, p_inet_ntoa(a), buflen);\r
668         buf[buflen-1] = '\0';\r
669     } else {\r
670         strncpy(buf, addr->hostname, buflen);\r
671         buf[buflen-1] = '\0';\r
672     }\r
675 int sk_hostname_is_local(const char *name)\r
677     return !strcmp(name, "localhost") ||\r
678            !strcmp(name, "::1") ||\r
679            !strncmp(name, "127.", 4);\r
682 static INTERFACE_INFO local_interfaces[16];\r
683 static int n_local_interfaces;       /* 0=not yet, -1=failed, >0=number */\r
685 static int ipv4_is_local_addr(struct in_addr addr)\r
687     if (ipv4_is_loopback(addr))\r
688         return 1;                      /* loopback addresses are local */\r
689     if (!n_local_interfaces) {\r
690         SOCKET s = p_socket(AF_INET, SOCK_DGRAM, 0);\r
691         DWORD retbytes;\r
693         if (p_WSAIoctl &&\r
694             p_WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0,\r
695                        local_interfaces, sizeof(local_interfaces),\r
696                        &retbytes, NULL, NULL) == 0)\r
697             n_local_interfaces = retbytes / sizeof(INTERFACE_INFO);\r
698         else\r
699             logevent(NULL, "Unable to get list of local IP addresses");\r
700     }\r
701     if (n_local_interfaces > 0) {\r
702         int i;\r
703         for (i = 0; i < n_local_interfaces; i++) {\r
704             SOCKADDR_IN *address =\r
705                 (SOCKADDR_IN *)&local_interfaces[i].iiAddress;\r
706             if (address->sin_addr.s_addr == addr.s_addr)\r
707                 return 1;              /* this address is local */\r
708         }\r
709     }\r
710     return 0;                  /* this address is not local */\r
713 int sk_address_is_local(SockAddr addr)\r
715     SockAddrStep step;\r
716     int family;\r
717     START_STEP(addr, step);\r
718     family = SOCKADDR_FAMILY(addr, step);\r
720 #ifndef NO_IPV6\r
721     if (family == AF_INET6) {\r
722         return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6 *)step.ai->ai_addr)->sin6_addr);\r
723     } else\r
724 #endif\r
725     if (family == AF_INET) {\r
726 #ifndef NO_IPV6\r
727         if (step.ai) {\r
728             return ipv4_is_local_addr(((struct sockaddr_in *)step.ai->ai_addr)\r
729                                       ->sin_addr);\r
730         } else\r
731 #endif\r
732         {\r
733             struct in_addr a;\r
734             assert(addr->addresses && step.curraddr < addr->naddresses);\r
735             a.s_addr = p_htonl(addr->addresses[step.curraddr]);\r
736             return ipv4_is_local_addr(a);\r
737         }\r
738     } else {\r
739         assert(family == AF_UNSPEC);\r
740         return 0;                      /* we don't know; assume not */\r
741     }\r
744 int sk_address_is_special_local(SockAddr addr)\r
746     return 0;                /* no Unix-domain socket analogue here */\r
749 int sk_addrtype(SockAddr addr)\r
751     SockAddrStep step;\r
752     int family;\r
753     START_STEP(addr, step);\r
754     family = SOCKADDR_FAMILY(addr, step);\r
756     return (family == AF_INET ? ADDRTYPE_IPV4 :\r
757 #ifndef NO_IPV6\r
758             family == AF_INET6 ? ADDRTYPE_IPV6 :\r
759 #endif\r
760             ADDRTYPE_NAME);\r
763 void sk_addrcopy(SockAddr addr, char *buf)\r
765     SockAddrStep step;\r
766     int family;\r
767     START_STEP(addr, step);\r
768     family = SOCKADDR_FAMILY(addr, step);\r
770     assert(family != AF_UNSPEC);\r
771 #ifndef NO_IPV6\r
772     if (step.ai) {\r
773         if (family == AF_INET)\r
774             memcpy(buf, &((struct sockaddr_in *)step.ai->ai_addr)->sin_addr,\r
775                    sizeof(struct in_addr));\r
776         else if (family == AF_INET6)\r
777             memcpy(buf, &((struct sockaddr_in6 *)step.ai->ai_addr)->sin6_addr,\r
778                    sizeof(struct in6_addr));\r
779         else\r
780             assert(FALSE);\r
781     } else\r
782 #endif\r
783     if (family == AF_INET) {\r
784         struct in_addr a;\r
785         assert(addr->addresses && step.curraddr < addr->naddresses);\r
786         a.s_addr = p_htonl(addr->addresses[step.curraddr]);\r
787         memcpy(buf, (char*) &a.s_addr, 4);\r
788     }\r
791 void sk_addr_free(SockAddr addr)\r
793     if (--addr->refcount > 0)\r
794         return;\r
795 #ifndef NO_IPV6\r
796     if (addr->ais && p_freeaddrinfo)\r
797         p_freeaddrinfo(addr->ais);\r
798 #endif\r
799     if (addr->addresses)\r
800         sfree(addr->addresses);\r
801     sfree(addr);\r
804 SockAddr sk_addr_dup(SockAddr addr)\r
806     addr->refcount++;\r
807     return addr;\r
810 static Plug sk_tcp_plug(Socket sock, Plug p)\r
812     Actual_Socket s = (Actual_Socket) sock;\r
813     Plug ret = s->plug;\r
814     if (p)\r
815         s->plug = p;\r
816     return ret;\r
819 static void sk_tcp_flush(Socket s)\r
821     /*\r
822      * We send data to the socket as soon as we can anyway,\r
823      * so we don't need to do anything here.  :-)\r
824      */\r
827 static void sk_tcp_close(Socket s);\r
828 static int sk_tcp_write(Socket s, const char *data, int len);\r
829 static int sk_tcp_write_oob(Socket s, const char *data, int len);\r
830 static void sk_tcp_write_eof(Socket s);\r
831 static void sk_tcp_set_private_ptr(Socket s, void *ptr);\r
832 static void *sk_tcp_get_private_ptr(Socket s);\r
833 static void sk_tcp_set_frozen(Socket s, int is_frozen);\r
834 static const char *sk_tcp_socket_error(Socket s);\r
836 extern char *do_select(SOCKET skt, int startup);\r
838 Socket sk_register(void *sock, Plug plug)\r
840     static const struct socket_function_table fn_table = {\r
841         sk_tcp_plug,\r
842         sk_tcp_close,\r
843         sk_tcp_write,\r
844         sk_tcp_write_oob,\r
845         sk_tcp_write_eof,\r
846         sk_tcp_flush,\r
847         sk_tcp_set_private_ptr,\r
848         sk_tcp_get_private_ptr,\r
849         sk_tcp_set_frozen,\r
850         sk_tcp_socket_error\r
851     };\r
853     DWORD err;\r
854     char *errstr;\r
855     Actual_Socket ret;\r
857     /*\r
858      * Create Socket structure.\r
859      */\r
860     ret = snew(struct Socket_tag);\r
861     ret->fn = &fn_table;\r
862     ret->error = NULL;\r
863     ret->plug = plug;\r
864     bufchain_init(&ret->output_data);\r
865     ret->writable = 1;                 /* to start with */\r
866     ret->sending_oob = 0;\r
867     ret->outgoingeof = EOF_NO;\r
868     ret->frozen = 1;\r
869     ret->frozen_readable = 0;\r
870     ret->localhost_only = 0;           /* unused, but best init anyway */\r
871     ret->pending_error = 0;\r
872     ret->parent = ret->child = NULL;\r
873     ret->addr = NULL;\r
875     ret->s = (SOCKET)sock;\r
877     if (ret->s == INVALID_SOCKET) {\r
878         err = p_WSAGetLastError();\r
879         ret->error = winsock_error_string(err);\r
880         return (Socket) ret;\r
881     }\r
883     ret->oobinline = 0;\r
885     /* Set up a select mechanism. This could be an AsyncSelect on a\r
886      * window, or an EventSelect on an event object. */\r
887     errstr = do_select(ret->s, 1);\r
888     if (errstr) {\r
889         ret->error = errstr;\r
890         return (Socket) ret;\r
891     }\r
893     add234(sktree, ret);\r
895     return (Socket) ret;\r
898 static DWORD try_connect(Actual_Socket sock)\r
900     SOCKET s;\r
901 #ifndef NO_IPV6\r
902     SOCKADDR_IN6 a6;\r
903 #endif\r
904     SOCKADDR_IN a;\r
905     DWORD err;\r
906     char *errstr;\r
907     short localport;\r
908     int family;\r
910     if (sock->s != INVALID_SOCKET) {\r
911         do_select(sock->s, 0);\r
912         p_closesocket(sock->s);\r
913     }\r
915     plug_log(sock->plug, 0, sock->addr, sock->port, NULL, 0);\r
917     /*\r
918      * Open socket.\r
919      */\r
920     family = SOCKADDR_FAMILY(sock->addr, sock->step);\r
922     /*\r
923      * Remove the socket from the tree before we overwrite its\r
924      * internal socket id, because that forms part of the tree's\r
925      * sorting criterion. We'll add it back before exiting this\r
926      * function, whether we changed anything or not.\r
927      */\r
928     del234(sktree, sock);\r
930     s = p_socket(family, SOCK_STREAM, 0);\r
931     sock->s = s;\r
933     if (s == INVALID_SOCKET) {\r
934         err = p_WSAGetLastError();\r
935         sock->error = winsock_error_string(err);\r
936         goto ret;\r
937     }\r
939     if (sock->oobinline) {\r
940         BOOL b = TRUE;\r
941         p_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b));\r
942     }\r
944     if (sock->nodelay) {\r
945         BOOL b = TRUE;\r
946         p_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b));\r
947     }\r
949     if (sock->keepalive) {\r
950         BOOL b = TRUE;\r
951         p_setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b));\r
952     }\r
954     /*\r
955      * Bind to local address.\r
956      */\r
957     if (sock->privport)\r
958         localport = 1023;              /* count from 1023 downwards */\r
959     else\r
960         localport = 0;                 /* just use port 0 (ie winsock picks) */\r
962     /* Loop round trying to bind */\r
963     while (1) {\r
964         int sockcode;\r
966 #ifndef NO_IPV6\r
967         if (family == AF_INET6) {\r
968             memset(&a6, 0, sizeof(a6));\r
969             a6.sin6_family = AF_INET6;\r
970           /*a6.sin6_addr = in6addr_any; */ /* == 0 done by memset() */\r
971             a6.sin6_port = p_htons(localport);\r
972         } else\r
973 #endif\r
974         {\r
975             a.sin_family = AF_INET;\r
976             a.sin_addr.s_addr = p_htonl(INADDR_ANY);\r
977             a.sin_port = p_htons(localport);\r
978         }\r
979 #ifndef NO_IPV6\r
980         sockcode = p_bind(s, (family == AF_INET6 ?\r
981                               (struct sockaddr *) &a6 :\r
982                               (struct sockaddr *) &a),\r
983                           (family == AF_INET6 ? sizeof(a6) : sizeof(a)));\r
984 #else\r
985         sockcode = p_bind(s, (struct sockaddr *) &a, sizeof(a));\r
986 #endif\r
987         if (sockcode != SOCKET_ERROR) {\r
988             err = 0;\r
989             break;                     /* done */\r
990         } else {\r
991             err = p_WSAGetLastError();\r
992             if (err != WSAEADDRINUSE)  /* failed, for a bad reason */\r
993                 break;\r
994         }\r
996         if (localport == 0)\r
997             break;                     /* we're only looping once */\r
998         localport--;\r
999         if (localport == 0)\r
1000             break;                     /* we might have got to the end */\r
1001     }\r
1003     if (err) {\r
1004         sock->error = winsock_error_string(err);\r
1005         goto ret;\r
1006     }\r
1008     /*\r
1009      * Connect to remote address.\r
1010      */\r
1011 #ifndef NO_IPV6\r
1012     if (sock->step.ai) {\r
1013         if (family == AF_INET6) {\r
1014             a6.sin6_family = AF_INET6;\r
1015             a6.sin6_port = p_htons((short) sock->port);\r
1016             a6.sin6_addr =\r
1017                 ((struct sockaddr_in6 *) sock->step.ai->ai_addr)->sin6_addr;\r
1018             a6.sin6_flowinfo = ((struct sockaddr_in6 *) sock->step.ai->ai_addr)->sin6_flowinfo;\r
1019             a6.sin6_scope_id = ((struct sockaddr_in6 *) sock->step.ai->ai_addr)->sin6_scope_id;\r
1020         } else {\r
1021             a.sin_family = AF_INET;\r
1022             a.sin_addr =\r
1023                 ((struct sockaddr_in *) sock->step.ai->ai_addr)->sin_addr;\r
1024             a.sin_port = p_htons((short) sock->port);\r
1025         }\r
1026     } else\r
1027 #endif\r
1028     {\r
1029         assert(sock->addr->addresses && sock->step.curraddr < sock->addr->naddresses);\r
1030         a.sin_family = AF_INET;\r
1031         a.sin_addr.s_addr = p_htonl(sock->addr->addresses[sock->step.curraddr]);\r
1032         a.sin_port = p_htons((short) sock->port);\r
1033     }\r
1035     /* Set up a select mechanism. This could be an AsyncSelect on a\r
1036      * window, or an EventSelect on an event object. */\r
1037     errstr = do_select(s, 1);\r
1038     if (errstr) {\r
1039         sock->error = errstr;\r
1040         err = 1;\r
1041         goto ret;\r
1042     }\r
1044     if ((\r
1045 #ifndef NO_IPV6\r
1046             p_connect(s,\r
1047                       ((family == AF_INET6) ? (struct sockaddr *) &a6 :\r
1048                        (struct sockaddr *) &a),\r
1049                       (family == AF_INET6) ? sizeof(a6) : sizeof(a))\r
1050 #else\r
1051             p_connect(s, (struct sockaddr *) &a, sizeof(a))\r
1052 #endif\r
1053         ) == SOCKET_ERROR) {\r
1054         err = p_WSAGetLastError();\r
1055         /*\r
1056          * We expect a potential EWOULDBLOCK here, because the\r
1057          * chances are the front end has done a select for\r
1058          * FD_CONNECT, so that connect() will complete\r
1059          * asynchronously.\r
1060          */\r
1061         if ( err != WSAEWOULDBLOCK ) {\r
1062             sock->error = winsock_error_string(err);\r
1063             goto ret;\r
1064         }\r
1065     } else {\r
1066         /*\r
1067          * If we _don't_ get EWOULDBLOCK, the connect has completed\r
1068          * and we should set the socket as writable.\r
1069          */\r
1070         sock->writable = 1;\r
1071     }\r
1073     err = 0;\r
1075     ret:\r
1077     /*\r
1078      * No matter what happened, put the socket back in the tree.\r
1079      */\r
1080     add234(sktree, sock);\r
1082     if (err)\r
1083         plug_log(sock->plug, 1, sock->addr, sock->port, sock->error, err);\r
1084     return err;\r
1087 Socket sk_new(SockAddr addr, int port, int privport, int oobinline,\r
1088               int nodelay, int keepalive, Plug plug)\r
1090     static const struct socket_function_table fn_table = {\r
1091         sk_tcp_plug,\r
1092         sk_tcp_close,\r
1093         sk_tcp_write,\r
1094         sk_tcp_write_oob,\r
1095         sk_tcp_write_eof,\r
1096         sk_tcp_flush,\r
1097         sk_tcp_set_private_ptr,\r
1098         sk_tcp_get_private_ptr,\r
1099         sk_tcp_set_frozen,\r
1100         sk_tcp_socket_error\r
1101     };\r
1103     Actual_Socket ret;\r
1104     DWORD err;\r
1106     /*\r
1107      * Create Socket structure.\r
1108      */\r
1109     ret = snew(struct Socket_tag);\r
1110     ret->fn = &fn_table;\r
1111     ret->error = NULL;\r
1112     ret->plug = plug;\r
1113     bufchain_init(&ret->output_data);\r
1114     ret->connected = 0;                /* to start with */\r
1115     ret->writable = 0;                 /* to start with */\r
1116     ret->sending_oob = 0;\r
1117     ret->outgoingeof = EOF_NO;\r
1118     ret->frozen = 0;\r
1119     ret->frozen_readable = 0;\r
1120     ret->localhost_only = 0;           /* unused, but best init anyway */\r
1121     ret->pending_error = 0;\r
1122     ret->parent = ret->child = NULL;\r
1123     ret->oobinline = oobinline;\r
1124     ret->nodelay = nodelay;\r
1125     ret->keepalive = keepalive;\r
1126     ret->privport = privport;\r
1127     ret->port = port;\r
1128     ret->addr = addr;\r
1129     START_STEP(ret->addr, ret->step);\r
1130     ret->s = INVALID_SOCKET;\r
1132     err = 0;\r
1133     do {\r
1134         err = try_connect(ret);\r
1135     } while (err && sk_nextaddr(ret->addr, &ret->step));\r
1137     return (Socket) ret;\r
1140 Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,\r
1141                       int orig_address_family)\r
1143     static const struct socket_function_table fn_table = {\r
1144         sk_tcp_plug,\r
1145         sk_tcp_close,\r
1146         sk_tcp_write,\r
1147         sk_tcp_write_oob,\r
1148         sk_tcp_write_eof,\r
1149         sk_tcp_flush,\r
1150         sk_tcp_set_private_ptr,\r
1151         sk_tcp_get_private_ptr,\r
1152         sk_tcp_set_frozen,\r
1153         sk_tcp_socket_error\r
1154     };\r
1156     SOCKET s;\r
1157 #ifndef NO_IPV6\r
1158     SOCKADDR_IN6 a6;\r
1159 #endif\r
1160     SOCKADDR_IN a;\r
1162     DWORD err;\r
1163     char *errstr;\r
1164     Actual_Socket ret;\r
1165     int retcode;\r
1166     int on = 1;\r
1168     int address_family;\r
1170     /*\r
1171      * Create Socket structure.\r
1172      */\r
1173     ret = snew(struct Socket_tag);\r
1174     ret->fn = &fn_table;\r
1175     ret->error = NULL;\r
1176     ret->plug = plug;\r
1177     bufchain_init(&ret->output_data);\r
1178     ret->writable = 0;                 /* to start with */\r
1179     ret->sending_oob = 0;\r
1180     ret->outgoingeof = EOF_NO;\r
1181     ret->frozen = 0;\r
1182     ret->frozen_readable = 0;\r
1183     ret->localhost_only = local_host_only;\r
1184     ret->pending_error = 0;\r
1185     ret->parent = ret->child = NULL;\r
1186     ret->addr = NULL;\r
1188     /*\r
1189      * Translate address_family from platform-independent constants\r
1190      * into local reality.\r
1191      */\r
1192     address_family = (orig_address_family == ADDRTYPE_IPV4 ? AF_INET :\r
1193 #ifndef NO_IPV6\r
1194                       orig_address_family == ADDRTYPE_IPV6 ? AF_INET6 :\r
1195 #endif\r
1196                       AF_UNSPEC);\r
1198     /*\r
1199      * Our default, if passed the `don't care' value\r
1200      * ADDRTYPE_UNSPEC, is to listen on IPv4. If IPv6 is supported,\r
1201      * we will also set up a second socket listening on IPv6, but\r
1202      * the v4 one is primary since that ought to work even on\r
1203      * non-v6-supporting systems.\r
1204      */\r
1205     if (address_family == AF_UNSPEC) address_family = AF_INET;\r
1207     /*\r
1208      * Open socket.\r
1209      */\r
1210     s = p_socket(address_family, SOCK_STREAM, 0);\r
1211     ret->s = s;\r
1213     if (s == INVALID_SOCKET) {\r
1214         err = p_WSAGetLastError();\r
1215         ret->error = winsock_error_string(err);\r
1216         return (Socket) ret;\r
1217     }\r
1219     ret->oobinline = 0;\r
1221     p_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));\r
1223 #ifndef NO_IPV6\r
1224         if (address_family == AF_INET6) {\r
1225             memset(&a6, 0, sizeof(a6));\r
1226             a6.sin6_family = AF_INET6;\r
1227             /* FIXME: srcaddr is ignored for IPv6, because I (SGT) don't\r
1228              * know how to do it. :-)\r
1229              * (jeroen:) saddr is specified as an address.. eg 2001:db8::1\r
1230              * Thus we need either a parser that understands [2001:db8::1]:80\r
1231              * style addresses and/or enhance this to understand hostnames too. */\r
1232             if (local_host_only)\r
1233                 a6.sin6_addr = in6addr_loopback;\r
1234             else\r
1235                 a6.sin6_addr = in6addr_any;\r
1236             a6.sin6_port = p_htons(port);\r
1237         } else\r
1238 #endif\r
1239         {\r
1240             int got_addr = 0;\r
1241             a.sin_family = AF_INET;\r
1243             /*\r
1244              * Bind to source address. First try an explicitly\r
1245              * specified one...\r
1246              */\r
1247             if (srcaddr) {\r
1248                 a.sin_addr.s_addr = p_inet_addr(srcaddr);\r
1249                 if (a.sin_addr.s_addr != INADDR_NONE) {\r
1250                     /* Override localhost_only with specified listen addr. */\r
1251                     ret->localhost_only = ipv4_is_loopback(a.sin_addr);\r
1252                     got_addr = 1;\r
1253                 }\r
1254             }\r
1256             /*\r
1257              * ... and failing that, go with one of the standard ones.\r
1258              */\r
1259             if (!got_addr) {\r
1260                 if (local_host_only)\r
1261                     a.sin_addr.s_addr = p_htonl(INADDR_LOOPBACK);\r
1262                 else\r
1263                     a.sin_addr.s_addr = p_htonl(INADDR_ANY);\r
1264             }\r
1266             a.sin_port = p_htons((short)port);\r
1267         }\r
1268 #ifndef NO_IPV6\r
1269         retcode = p_bind(s, (address_family == AF_INET6 ?\r
1270                            (struct sockaddr *) &a6 :\r
1271                            (struct sockaddr *) &a),\r
1272                        (address_family ==\r
1273                         AF_INET6 ? sizeof(a6) : sizeof(a)));\r
1274 #else\r
1275         retcode = p_bind(s, (struct sockaddr *) &a, sizeof(a));\r
1276 #endif\r
1277         if (retcode != SOCKET_ERROR) {\r
1278             err = 0;\r
1279         } else {\r
1280             err = p_WSAGetLastError();\r
1281         }\r
1283     if (err) {\r
1284         p_closesocket(s);\r
1285         ret->error = winsock_error_string(err);\r
1286         return (Socket) ret;\r
1287     }\r
1290     if (p_listen(s, SOMAXCONN) == SOCKET_ERROR) {\r
1291         p_closesocket(s);\r
1292         ret->error = winsock_error_string(p_WSAGetLastError());\r
1293         return (Socket) ret;\r
1294     }\r
1296     /* Set up a select mechanism. This could be an AsyncSelect on a\r
1297      * window, or an EventSelect on an event object. */\r
1298     errstr = do_select(s, 1);\r
1299     if (errstr) {\r
1300         p_closesocket(s);\r
1301         ret->error = errstr;\r
1302         return (Socket) ret;\r
1303     }\r
1305     add234(sktree, ret);\r
1307 #ifndef NO_IPV6\r
1308     /*\r
1309      * If we were given ADDRTYPE_UNSPEC, we must also create an\r
1310      * IPv6 listening socket and link it to this one.\r
1311      */\r
1312     if (address_family == AF_INET && orig_address_family == ADDRTYPE_UNSPEC) {\r
1313         Actual_Socket other;\r
1315         other = (Actual_Socket) sk_newlistener(srcaddr, port, plug,\r
1316                                                local_host_only, ADDRTYPE_IPV6);\r
1318         if (other) {\r
1319             if (!other->error) {\r
1320                 other->parent = ret;\r
1321                 ret->child = other;\r
1322             } else {\r
1323                 sfree(other);\r
1324             }\r
1325         }\r
1326     }\r
1327 #endif\r
1329     return (Socket) ret;\r
1332 static void sk_tcp_close(Socket sock)\r
1334     extern char *do_select(SOCKET skt, int startup);\r
1335     Actual_Socket s = (Actual_Socket) sock;\r
1337     if (s->child)\r
1338         sk_tcp_close((Socket)s->child);\r
1340     del234(sktree, s);\r
1341     do_select(s->s, 0);\r
1342     p_closesocket(s->s);\r
1343     if (s->addr)\r
1344         sk_addr_free(s->addr);\r
1345     sfree(s);\r
1348 /*\r
1349  * The function which tries to send on a socket once it's deemed\r
1350  * writable.\r
1351  */\r
1352 void try_send(Actual_Socket s)\r
1354     while (s->sending_oob || bufchain_size(&s->output_data) > 0) {\r
1355         int nsent;\r
1356         DWORD err;\r
1357         void *data;\r
1358         int len, urgentflag;\r
1360         if (s->sending_oob) {\r
1361             urgentflag = MSG_OOB;\r
1362             len = s->sending_oob;\r
1363             data = &s->oobdata;\r
1364         } else {\r
1365             urgentflag = 0;\r
1366             bufchain_prefix(&s->output_data, &data, &len);\r
1367         }\r
1368         nsent = p_send(s->s, data, len, urgentflag);\r
1369         noise_ultralight(nsent);\r
1370         if (nsent <= 0) {\r
1371             err = (nsent < 0 ? p_WSAGetLastError() : 0);\r
1372             if ((err < WSABASEERR && nsent < 0) || err == WSAEWOULDBLOCK) {\r
1373                 /*\r
1374                  * Perfectly normal: we've sent all we can for the moment.\r
1375                  * \r
1376                  * (Some WinSock send() implementations can return\r
1377                  * <0 but leave no sensible error indication -\r
1378                  * WSAGetLastError() is called but returns zero or\r
1379                  * a small number - so we check that case and treat\r
1380                  * it just like WSAEWOULDBLOCK.)\r
1381                  */\r
1382                 s->writable = FALSE;\r
1383                 return;\r
1384             } else if (nsent == 0 ||\r
1385                        err == WSAECONNABORTED || err == WSAECONNRESET) {\r
1386                 /*\r
1387                  * If send() returns CONNABORTED or CONNRESET, we\r
1388                  * unfortunately can't just call plug_closing(),\r
1389                  * because it's quite likely that we're currently\r
1390                  * _in_ a call from the code we'd be calling back\r
1391                  * to, so we'd have to make half the SSH code\r
1392                  * reentrant. Instead we flag a pending error on\r
1393                  * the socket, to be dealt with (by calling\r
1394                  * plug_closing()) at some suitable future moment.\r
1395                  */\r
1396                 s->pending_error = err;\r
1397                 return;\r
1398             } else {\r
1399                 /* We're inside the Windows frontend here, so we know\r
1400                  * that the frontend handle is unnecessary. */\r
1401                 logevent(NULL, winsock_error_string(err));\r
1402                 fatalbox("%s", winsock_error_string(err));\r
1403             }\r
1404         } else {\r
1405             if (s->sending_oob) {\r
1406                 if (nsent < len) {\r
1407                     memmove(s->oobdata, s->oobdata+nsent, len-nsent);\r
1408                     s->sending_oob = len - nsent;\r
1409                 } else {\r
1410                     s->sending_oob = 0;\r
1411                 }\r
1412             } else {\r
1413                 bufchain_consume(&s->output_data, nsent);\r
1414             }\r
1415         }\r
1416     }\r
1418     /*\r
1419      * If we reach here, we've finished sending everything we might\r
1420      * have needed to send. Send EOF, if we need to.\r
1421      */\r
1422     if (s->outgoingeof == EOF_PENDING) {\r
1423         p_shutdown(s->s, SD_SEND);\r
1424         s->outgoingeof = EOF_SENT;\r
1425     }\r
1428 static int sk_tcp_write(Socket sock, const char *buf, int len)\r
1430     Actual_Socket s = (Actual_Socket) sock;\r
1432     assert(s->outgoingeof == EOF_NO);\r
1434     /*\r
1435      * Add the data to the buffer list on the socket.\r
1436      */\r
1437     bufchain_add(&s->output_data, buf, len);\r
1439     /*\r
1440      * Now try sending from the start of the buffer list.\r
1441      */\r
1442     if (s->writable)\r
1443         try_send(s);\r
1445     return bufchain_size(&s->output_data);\r
1448 static int sk_tcp_write_oob(Socket sock, const char *buf, int len)\r
1450     Actual_Socket s = (Actual_Socket) sock;\r
1452     assert(s->outgoingeof == EOF_NO);\r
1454     /*\r
1455      * Replace the buffer list on the socket with the data.\r
1456      */\r
1457     bufchain_clear(&s->output_data);\r
1458     assert(len <= sizeof(s->oobdata));\r
1459     memcpy(s->oobdata, buf, len);\r
1460     s->sending_oob = len;\r
1462     /*\r
1463      * Now try sending from the start of the buffer list.\r
1464      */\r
1465     if (s->writable)\r
1466         try_send(s);\r
1468     return s->sending_oob;\r
1471 static void sk_tcp_write_eof(Socket sock)\r
1473     Actual_Socket s = (Actual_Socket) sock;\r
1475     assert(s->outgoingeof == EOF_NO);\r
1477     /*\r
1478      * Mark the socket as pending outgoing EOF.\r
1479      */\r
1480     s->outgoingeof = EOF_PENDING;\r
1482     /*\r
1483      * Now try sending from the start of the buffer list.\r
1484      */\r
1485     if (s->writable)\r
1486         try_send(s);\r
1489 int select_result(WPARAM wParam, LPARAM lParam)\r
1491     int ret, open;\r
1492     DWORD err;\r
1493     char buf[20480];                   /* nice big buffer for plenty of speed */\r
1494     Actual_Socket s;\r
1495     u_long atmark;\r
1497     /* wParam is the socket itself */\r
1499     if (wParam == 0)\r
1500         return 1;                      /* boggle */\r
1502     s = find234(sktree, (void *) wParam, cmpforsearch);\r
1503     if (!s)\r
1504         return 1;                      /* boggle */\r
1506     if ((err = WSAGETSELECTERROR(lParam)) != 0) {\r
1507         /*\r
1508          * An error has occurred on this socket. Pass it to the\r
1509          * plug.\r
1510          */\r
1511         if (s->addr) {\r
1512             plug_log(s->plug, 1, s->addr, s->port,\r
1513                      winsock_error_string(err), err);\r
1514             while (s->addr && sk_nextaddr(s->addr, &s->step)) {\r
1515                 err = try_connect(s);\r
1516             }\r
1517         }\r
1518         if (err != 0)\r
1519             return plug_closing(s->plug, winsock_error_string(err), err, 0);\r
1520         else\r
1521             return 1;\r
1522     }\r
1524     noise_ultralight(lParam);\r
1526     switch (WSAGETSELECTEVENT(lParam)) {\r
1527       case FD_CONNECT:\r
1528         s->connected = s->writable = 1;\r
1529         /*\r
1530          * Once a socket is connected, we can stop falling\r
1531          * back through the candidate addresses to connect\r
1532          * to.\r
1533          */\r
1534         if (s->addr) {\r
1535             sk_addr_free(s->addr);\r
1536             s->addr = NULL;\r
1537         }\r
1538         break;\r
1539       case FD_READ:\r
1540         /* In the case the socket is still frozen, we don't even bother */\r
1541         if (s->frozen) {\r
1542             s->frozen_readable = 1;\r
1543             break;\r
1544         }\r
1546         /*\r
1547          * We have received data on the socket. For an oobinline\r
1548          * socket, this might be data _before_ an urgent pointer,\r
1549          * in which case we send it to the back end with type==1\r
1550          * (data prior to urgent).\r
1551          */\r
1552         if (s->oobinline) {\r
1553             atmark = 1;\r
1554             p_ioctlsocket(s->s, SIOCATMARK, &atmark);\r
1555             /*\r
1556              * Avoid checking the return value from ioctlsocket(),\r
1557              * on the grounds that some WinSock wrappers don't\r
1558              * support it. If it does nothing, we get atmark==1,\r
1559              * which is equivalent to `no OOB pending', so the\r
1560              * effect will be to non-OOB-ify any OOB data.\r
1561              */\r
1562         } else\r
1563             atmark = 1;\r
1565         ret = p_recv(s->s, buf, sizeof(buf), 0);\r
1566         noise_ultralight(ret);\r
1567         if (ret < 0) {\r
1568             err = p_WSAGetLastError();\r
1569             if (err == WSAEWOULDBLOCK) {\r
1570                 break;\r
1571             }\r
1572         }\r
1573         if (ret < 0) {\r
1574             return plug_closing(s->plug, winsock_error_string(err), err,\r
1575                                 0);\r
1576         } else if (0 == ret) {\r
1577             return plug_closing(s->plug, NULL, 0, 0);\r
1578         } else {\r
1579             return plug_receive(s->plug, atmark ? 0 : 1, buf, ret);\r
1580         }\r
1581         break;\r
1582       case FD_OOB:\r
1583         /*\r
1584          * This will only happen on a non-oobinline socket. It\r
1585          * indicates that we can immediately perform an OOB read\r
1586          * and get back OOB data, which we will send to the back\r
1587          * end with type==2 (urgent data).\r
1588          */\r
1589         ret = p_recv(s->s, buf, sizeof(buf), MSG_OOB);\r
1590         noise_ultralight(ret);\r
1591         if (ret <= 0) {\r
1592             char *str = (ret == 0 ? "Internal networking trouble" :\r
1593                          winsock_error_string(p_WSAGetLastError()));\r
1594             /* We're inside the Windows frontend here, so we know\r
1595              * that the frontend handle is unnecessary. */\r
1596             logevent(NULL, str);\r
1597             fatalbox("%s", str);\r
1598         } else {\r
1599             return plug_receive(s->plug, 2, buf, ret);\r
1600         }\r
1601         break;\r
1602       case FD_WRITE:\r
1603         {\r
1604             int bufsize_before, bufsize_after;\r
1605             s->writable = 1;\r
1606             bufsize_before = s->sending_oob + bufchain_size(&s->output_data);\r
1607             try_send(s);\r
1608             bufsize_after = s->sending_oob + bufchain_size(&s->output_data);\r
1609             if (bufsize_after < bufsize_before)\r
1610                 plug_sent(s->plug, bufsize_after);\r
1611         }\r
1612         break;\r
1613       case FD_CLOSE:\r
1614         /* Signal a close on the socket. First read any outstanding data. */\r
1615         open = 1;\r
1616         do {\r
1617             ret = p_recv(s->s, buf, sizeof(buf), 0);\r
1618             if (ret < 0) {\r
1619                 err = p_WSAGetLastError();\r
1620                 if (err == WSAEWOULDBLOCK)\r
1621                     break;\r
1622                 return plug_closing(s->plug, winsock_error_string(err),\r
1623                                     err, 0);\r
1624             } else {\r
1625                 if (ret)\r
1626                     open &= plug_receive(s->plug, 0, buf, ret);\r
1627                 else\r
1628                     open &= plug_closing(s->plug, NULL, 0, 0);\r
1629             }\r
1630         } while (ret > 0);\r
1631         return open;\r
1632        case FD_ACCEPT:\r
1633         {\r
1634 #ifdef NO_IPV6\r
1635             struct sockaddr_in isa;\r
1636 #else\r
1637             struct sockaddr_storage isa;\r
1638 #endif\r
1639             int addrlen = sizeof(isa);\r
1640             SOCKET t;  /* socket of connection */\r
1642             memset(&isa, 0, sizeof(isa));\r
1643             err = 0;\r
1644             t = p_accept(s->s,(struct sockaddr *)&isa,&addrlen);\r
1645             if (t == INVALID_SOCKET)\r
1646             {\r
1647                 err = p_WSAGetLastError();\r
1648                 if (err == WSATRY_AGAIN)\r
1649                     break;\r
1650             }\r
1651 #ifndef NO_IPV6\r
1652             if (isa.ss_family == AF_INET &&\r
1653                 s->localhost_only &&\r
1654                 !ipv4_is_local_addr(((struct sockaddr_in *)&isa)->sin_addr))\r
1655 #else\r
1656             if (s->localhost_only && !ipv4_is_local_addr(isa.sin_addr))\r
1657 #endif\r
1658             {\r
1659                 p_closesocket(t);      /* dodgy WinSock let nonlocal through */\r
1660             } else if (plug_accepting(s->plug, (void*)t)) {\r
1661                 p_closesocket(t);      /* denied or error */\r
1662             }\r
1663         }\r
1664     }\r
1666     return 1;\r
1669 /*\r
1670  * Deal with socket errors detected in try_send().\r
1671  */\r
1672 void net_pending_errors(void)\r
1674     int i;\r
1675     Actual_Socket s;\r
1677     /*\r
1678      * This might be a fiddly business, because it's just possible\r
1679      * that handling a pending error on one socket might cause\r
1680      * others to be closed. (I can't think of any reason this might\r
1681      * happen in current SSH implementation, but to maintain\r
1682      * generality of this network layer I'll assume the worst.)\r
1683      * \r
1684      * So what we'll do is search the socket list for _one_ socket\r
1685      * with a pending error, and then handle it, and then search\r
1686      * the list again _from the beginning_. Repeat until we make a\r
1687      * pass with no socket errors present. That way we are\r
1688      * protected against the socket list changing under our feet.\r
1689      */\r
1691     do {\r
1692         for (i = 0; (s = index234(sktree, i)) != NULL; i++) {\r
1693             if (s->pending_error) {\r
1694                 /*\r
1695                  * An error has occurred on this socket. Pass it to the\r
1696                  * plug.\r
1697                  */\r
1698                 plug_closing(s->plug,\r
1699                              winsock_error_string(s->pending_error),\r
1700                              s->pending_error, 0);\r
1701                 break;\r
1702             }\r
1703         }\r
1704     } while (s);\r
1707 /*\r
1708  * Each socket abstraction contains a `void *' private field in\r
1709  * which the client can keep state.\r
1710  */\r
1711 static void sk_tcp_set_private_ptr(Socket sock, void *ptr)\r
1713     Actual_Socket s = (Actual_Socket) sock;\r
1714     s->private_ptr = ptr;\r
1717 static void *sk_tcp_get_private_ptr(Socket sock)\r
1719     Actual_Socket s = (Actual_Socket) sock;\r
1720     return s->private_ptr;\r
1723 /*\r
1724  * Special error values are returned from sk_namelookup and sk_new\r
1725  * if there's a problem. These functions extract an error message,\r
1726  * or return NULL if there's no problem.\r
1727  */\r
1728 const char *sk_addr_error(SockAddr addr)\r
1730     return addr->error;\r
1732 static const char *sk_tcp_socket_error(Socket sock)\r
1734     Actual_Socket s = (Actual_Socket) sock;\r
1735     return s->error;\r
1738 static void sk_tcp_set_frozen(Socket sock, int is_frozen)\r
1740     Actual_Socket s = (Actual_Socket) sock;\r
1741     if (s->frozen == is_frozen)\r
1742         return;\r
1743     s->frozen = is_frozen;\r
1744     if (!is_frozen) {\r
1745         do_select(s->s, 1);\r
1746         if (s->frozen_readable) {\r
1747             char c;\r
1748             p_recv(s->s, &c, 1, MSG_PEEK);\r
1749         }\r
1750     }\r
1751     s->frozen_readable = 0;\r
1754 void socket_reselect_all(void)\r
1756     Actual_Socket s;\r
1757     int i;\r
1759     for (i = 0; (s = index234(sktree, i)) != NULL; i++) {\r
1760         if (!s->frozen)\r
1761             do_select(s->s, 1);\r
1762     }\r
1765 /*\r
1766  * For Plink: enumerate all sockets currently active.\r
1767  */\r
1768 SOCKET first_socket(int *state)\r
1770     Actual_Socket s;\r
1771     *state = 0;\r
1772     s = index234(sktree, (*state)++);\r
1773     return s ? s->s : INVALID_SOCKET;\r
1776 SOCKET next_socket(int *state)\r
1778     Actual_Socket s = index234(sktree, (*state)++);\r
1779     return s ? s->s : INVALID_SOCKET;\r
1782 extern int socket_writable(SOCKET skt)\r
1784     Actual_Socket s = find234(sktree, (void *)skt, cmpforsearch);\r
1786     if (s)\r
1787         return bufchain_size(&s->output_data) > 0;\r
1788     else\r
1789         return 0;\r
1792 int net_service_lookup(char *service)\r
1794     struct servent *se;\r
1795     se = p_getservbyname(service, NULL);\r
1796     if (se != NULL)\r
1797         return p_ntohs(se->s_port);\r
1798     else\r
1799         return 0;\r
1802 char *get_hostname(void)\r
1804     int len = 128;\r
1805     char *hostname = NULL;\r
1806     do {\r
1807         len *= 2;\r
1808         hostname = sresize(hostname, len, char);\r
1809         if (p_gethostname(hostname, len) < 0) {\r
1810             sfree(hostname);\r
1811             hostname = NULL;\r
1812             break;\r
1813         }\r
1814     } while (strlen(hostname) >= (size_t)(len-1));\r
1815     return hostname;\r
1818 SockAddr platform_get_x11_unix_address(const char *display, int displaynum,\r
1819                                        char **canonicalname)\r
1821     SockAddr ret = snew(struct SockAddr_tag);\r
1822     memset(ret, 0, sizeof(struct SockAddr_tag));\r
1823     ret->error = "unix sockets not supported on this platform";\r
1824     ret->refcount = 1;\r
1825     return ret;\r