2 * Windows networking abstraction.
4 * Due to this clean abstraction it was possible
5 * to easily implement IPv6 support :)
7 * IPv6 patch 1 (27 October 2000) Jeroen Massar <jeroen@unfix.org>
8 * - Preliminary hacked IPv6 support.
9 * - Connecting to IPv6 address (eg fec0:4242:4242:100:2d0:b7ff:fe8f:5d42) works.
10 * - Connecting to IPv6 hostname (eg heaven.ipv6.unfix.org) works.
11 * - Compiles as either IPv4 or IPv6.
13 * IPv6 patch 2 (29 October 2000) Jeroen Massar <jeroen@unfix.org>
14 * - When compiled as IPv6 it also allows connecting to IPv4 hosts.
15 * - Added some more documentation.
17 * IPv6 patch 3 (18 November 2000) Jeroen Massar <jeroen@unfix.org>
18 * - It now supports dynamically loading the IPv6 resolver dll's.
19 * This way we should be able to distribute one (1) binary
20 * which supports both IPv4 and IPv6.
21 * - getaddrinfo() and getnameinfo() are loaded dynamicaly if possible.
22 * - in6addr_any is defined in this file so we don't need to link to wship6.lib
23 * - The patch is now more unified so that we can still
24 * remove all IPv6 support by undef'ing IPV6.
25 * But where it fallsback to IPv4 it uses the IPv4 code which is already in place...
26 * - Canonical name resolving works.
28 * IPv6 patch 4 (07 January 2001) Jeroen Massar <jeroen@unfix.org>
29 * - patch against CVS of today, will be submitted to the bugs list
30 * as a 'cvs diff -u' on Simon's request...
35 * Define IPV6 to have IPv6 on-the-fly-loading support.
36 * This means that one doesn't have to have an IPv6 stack to use it.
37 * But if an IPv6 stack is found it is used with a fallback to IPv4.
52 #define DEFINE_PLUG_METHOD_MACROS
57 #define BUFFER_GRANULE 512
60 struct socket_function_table
*fn
;
61 /* the above variable absolutely *must* be the first in this structure */
66 struct buffer
*head
, *tail
;
73 * We used to typedef struct Socket_tag *Socket.
75 * Since we have made the networking abstraction slightly more
76 * abstract, Socket no longer means a tcp socket (it could mean
77 * an ssl socket). So now we must use Actual_Socket when we know
78 * we are talking about a tcp socket.
80 typedef struct Socket_tag
*Actual_Socket
;
84 /* address family this belongs to, AF_INET for IPv4, AF_INET6 for IPv6. */
86 unsigned long address
; /* Address IPv4 style. */
88 struct addrinfo
*ai
; /* Address IPv6 style. */
91 * We need to have this lengthy enough to hold *any* hostname
92 * (including IPv6 reverse...)
100 char buf
[BUFFER_GRANULE
];
103 static tree234
*sktree
;
105 static int cmpfortree(void *av
, void *bv
) {
106 Actual_Socket a
= (Actual_Socket
)av
, b
= (Actual_Socket
)bv
;
107 unsigned long as
= (unsigned long)a
->s
, bs
= (unsigned long)b
->s
;
108 if (as
< bs
) return -1;
109 if (as
> bs
) return +1;
113 static int cmpforsearch(void *av
, void *bv
) {
114 Actual_Socket b
= (Actual_Socket
)bv
;
115 unsigned long as
= (unsigned long)av
, bs
= (unsigned long)b
->s
;
116 if (as
< bs
) return -1;
117 if (as
> bs
) return +1;
122 sktree
= newtree234(cmpfortree
);
125 char *winsock_error_string(int error
) {
127 case WSAEACCES
: return "Network error: Permission denied";
128 case WSAEADDRINUSE
: return "Network error: Address already in use";
129 case WSAEADDRNOTAVAIL
: return "Network error: Cannot assign requested address";
130 case WSAEAFNOSUPPORT
: return "Network error: Address family not supported by protocol family";
131 case WSAEALREADY
: return "Network error: Operation already in progress";
132 case WSAECONNABORTED
: return "Network error: Software caused connection abort";
133 case WSAECONNREFUSED
: return "Network error: Connection refused";
134 case WSAECONNRESET
: return "Network error: Connection reset by peer";
135 case WSAEDESTADDRREQ
: return "Network error: Destination address required";
136 case WSAEFAULT
: return "Network error: Bad address";
137 case WSAEHOSTDOWN
: return "Network error: Host is down";
138 case WSAEHOSTUNREACH
: return "Network error: No route to host";
139 case WSAEINPROGRESS
: return "Network error: Operation now in progress";
140 case WSAEINTR
: return "Network error: Interrupted function call";
141 case WSAEINVAL
: return "Network error: Invalid argument";
142 case WSAEISCONN
: return "Network error: Socket is already connected";
143 case WSAEMFILE
: return "Network error: Too many open files";
144 case WSAEMSGSIZE
: return "Network error: Message too long";
145 case WSAENETDOWN
: return "Network error: Network is down";
146 case WSAENETRESET
: return "Network error: Network dropped connection on reset";
147 case WSAENETUNREACH
: return "Network error: Network is unreachable";
148 case WSAENOBUFS
: return "Network error: No buffer space available";
149 case WSAENOPROTOOPT
: return "Network error: Bad protocol option";
150 case WSAENOTCONN
: return "Network error: Socket is not connected";
151 case WSAENOTSOCK
: return "Network error: Socket operation on non-socket";
152 case WSAEOPNOTSUPP
: return "Network error: Operation not supported";
153 case WSAEPFNOSUPPORT
: return "Network error: Protocol family not supported";
154 case WSAEPROCLIM
: return "Network error: Too many processes";
155 case WSAEPROTONOSUPPORT
: return "Network error: Protocol not supported";
156 case WSAEPROTOTYPE
: return "Network error: Protocol wrong type for socket";
157 case WSAESHUTDOWN
: return "Network error: Cannot send after socket shutdown";
158 case WSAESOCKTNOSUPPORT
: return "Network error: Socket type not supported";
159 case WSAETIMEDOUT
: return "Network error: Connection timed out";
160 case WSAEWOULDBLOCK
: return "Network error: Resource temporarily unavailable";
161 case WSAEDISCON
: return "Network error: Graceful shutdown in progress";
162 default: return "Unknown network error";
166 SockAddr
sk_namelookup(char *host
, char **canonicalname
)
168 SockAddr ret
= smalloc(sizeof(struct SockAddr_tag
));
170 struct hostent
*h
= NULL
;
172 /* Clear the structure and default to IPv4. */
173 memset(ret
, 0, sizeof(struct SockAddr_tag
));
174 ret
->family
= 0; /* We set this one when we have resolved the host. */
175 *canonicalname
= ret
->realhost
; /* This makes sure we always have a hostname to return. */
177 if ( (a
= inet_addr(host
)) == (unsigned long) INADDR_NONE
)
181 /* Try to get the getaddrinfo() function from wship6.dll */
182 /* This way one doesn't need to have IPv6 dll's to use PuTTY and
183 * it will fallback to IPv4. */
184 typedef int (CALLBACK
* FGETADDRINFO
)(const char *nodename
,
185 const char *servname
,
186 const struct addrinfo
*hints
,
187 struct addrinfo
**res
);
188 FGETADDRINFO fGetAddrInfo
= NULL
;
190 HINSTANCE dllWSHIP6
= LoadLibrary("wship6.dll");
192 fGetAddrInfo
= (FGETADDRINFO
)GetProcAddress(dllWSHIP6
,
196 * Use fGetAddrInfo when it's available (which usually also
197 * means IPv6 is installed...)
201 /*debug(("Resolving \"%s\" with getaddrinfo() (IPv4+IPv6 capable)...\n", host)); */
202 if (fGetAddrInfo(host
, NULL
, NULL
, &ret
->ai
) == 0)
203 ret
->family
= ret
->ai
->ai_family
;
208 * Otherwise use the IPv4-only gethostbyname...
209 * (NOTE: we don't use gethostbyname as a
212 if (ret
->family
== 0)
214 /*debug(("Resolving \"%s\" with gethostbyname() (IPv4 only)...\n", host)); */
215 if (h
= gethostbyname(host
)) ret
->family
= AF_INET
;
217 /*debug(("Done resolving...(family is %d) AF_INET = %d, AF_INET6 = %d\n", ret->family, AF_INET, AF_INET6)); */
219 if (ret
->family
== 0)
221 DWORD err
= WSAGetLastError();
222 ret
->error
= (err
== WSAENETDOWN ?
"Network is down" :
223 err
== WSAHOST_NOT_FOUND ?
"Host does not exist" :
224 err
== WSATRY_AGAIN ?
"Host not found" :
226 fGetAddrInfo ?
"getaddrinfo: unknown error" :
228 "gethostbyname: unknown error");
232 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
, NULL
, err
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), (LPTSTR
)&lpMsgBuf
, 0, NULL
);
233 /*debug(("Error %ld: %s (h=%lx)\n", err, lpMsgBuf, h));*/
234 /* Free the buffer. */
244 /* If we got an address info use that... */
247 typedef int (CALLBACK
* FGETNAMEINFO
)
248 (const struct sockaddr FAR
*sa
, socklen_t salen
,
249 char FAR
* host
, size_t hostlen
, char FAR
* serv
,
250 size_t servlen
, int flags
);
251 FGETNAMEINFO fGetNameInfo
= NULL
;
253 /* Are we in IPv4 fallback mode? */
254 /* We put the IPv4 address into the a variable so we can further-on use the IPv4 code... */
255 if (ret
->family
== AF_INET
)
256 memcpy(&a
, (char *)&((SOCKADDR_IN
*)ret
->ai
->ai_addr
)->sin_addr
, sizeof(a
));
258 /* Now let's find that canonicalname... */
259 if ((dllWSHIP6
) && (fGetNameInfo
= (FGETNAMEINFO
)GetProcAddress(dllWSHIP6
, "getnameinfo")))
261 if (fGetNameInfo((struct sockaddr
*)ret
->ai
->ai_addr
,
262 ret
->family
== AF_INET ?
263 sizeof(SOCKADDR_IN
) :
264 sizeof(SOCKADDR_IN6
), ret
->realhost
,
265 sizeof(ret
->realhost
), NULL
,
268 strncpy(ret
->realhost
, host
,
269 sizeof(ret
->realhost
));
273 /* We used the IPv4-only gethostbyname()... */
277 memcpy(&a
, h
->h_addr
, sizeof(a
));
278 /* This way we are always sure the h->h_name is valid :) */
279 strncpy(ret
->realhost
, h
->h_name
, sizeof(ret
->realhost
));
285 FreeLibrary(dllWSHIP6
);
291 * Hack inserted to deal with problems with numeric IPs.
292 * FIXME: how will this work in IPv6?
294 ret
->family
= AF_INET
;
295 *canonicalname
= host
;
297 ret
->address
= ntohl(a
);
301 void sk_addr_free(SockAddr addr
) {
305 static Plug
sk_tcp_plug (Socket sock
, Plug p
) {
306 Actual_Socket s
= (Actual_Socket
) sock
;
312 static void sk_tcp_flush (Socket s
) {
314 * We send data to the socket as soon as we can anyway,
315 * so we don't need to do anything here. :-)
319 void sk_tcp_close (Socket s
);
320 void sk_tcp_write (Socket s
, char *data
, int len
);
321 void sk_tcp_write_oob (Socket s
, char *data
, int len
);
322 char *sk_tcp_socket_error(Socket s
);
324 Socket
sk_new(SockAddr addr
, int port
, int privport
, int oobinline
,
327 static struct socket_function_table fn_table
= {
344 extern char *do_select(SOCKET skt
, int startup
);
348 * Create Socket structure.
350 ret
= smalloc(sizeof(struct Socket_tag
));
354 ret
->head
= ret
->tail
= NULL
;
355 ret
->writable
= 1; /* to start with */
356 ret
->sending_oob
= 0;
361 s
= socket(addr
->family
, SOCK_STREAM
, 0);
364 if (s
== INVALID_SOCKET
) {
365 err
= WSAGetLastError();
366 ret
->error
= winsock_error_string(err
);
370 ret
->oobinline
= oobinline
;
373 setsockopt (s
, SOL_SOCKET
, SO_OOBINLINE
, (void *)&b
, sizeof(b
));
377 * Bind to local address.
380 localport
= 1023; /* count from 1023 downwards */
382 localport
= 0; /* just use port 0 (ie winsock picks) */
384 /* Loop round trying to bind */
389 if (addr
->family
== AF_INET6
)
391 memset(&a6
,0,sizeof(a6
));
392 a6
.sin6_family
= AF_INET6
;
393 /*a6.sin6_addr = in6addr_any;*/ /* == 0 */
394 a6
.sin6_port
= htons(localport
);
399 a
.sin_family
= AF_INET
;
400 a
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
401 a
.sin_port
= htons(localport
);
404 retcode
= bind (s
, (addr
->family
== AF_INET6 ?
405 (struct sockaddr
*)&a6
:
406 (struct sockaddr
*)&a
),
407 (addr
->family
== AF_INET6 ?
sizeof(a6
) : sizeof(a
)));
409 retcode
= bind (s
, (struct sockaddr
*)&a
, sizeof(a
));
411 if (retcode
!= SOCKET_ERROR
) {
415 err
= WSAGetLastError();
416 if (err
!= WSAEADDRINUSE
) /* failed, for a bad reason */
421 break; /* we're only looping once */
424 break; /* we might have got to the end */
429 ret
->error
= winsock_error_string(err
);
434 * Connect to remote address.
437 if (addr
->family
== AF_INET6
)
439 memset(&a
,0,sizeof(a
));
440 a6
.sin6_family
= AF_INET6
;
441 a6
.sin6_port
= htons((short)port
);
442 a6
.sin6_addr
= ((struct sockaddr_in6
*)addr
->ai
->ai_addr
)->sin6_addr
;
447 a
.sin_family
= AF_INET
;
448 a
.sin_addr
.s_addr
= htonl(addr
->address
);
449 a
.sin_port
= htons((short)port
);
452 if (connect (s
, (addr
->family
== AF_INET6
) ?
(struct sockaddr
*)&a6
: (struct sockaddr
*)&a
, (addr
->family
== AF_INET6
) ?
sizeof(a6
) : sizeof(a
)) == SOCKET_ERROR
)
454 if (connect (s
, (struct sockaddr
*)&a
, sizeof(a
)) == SOCKET_ERROR
)
457 err
= WSAGetLastError();
458 ret
->error
= winsock_error_string(err
);
462 /* Set up a select mechanism. This could be an AsyncSelect on a
463 * window, or an EventSelect on an event object. */
464 errstr
= do_select(s
, 1);
475 static void sk_tcp_close(Socket sock
) {
476 extern char *do_select(SOCKET skt
, int startup
);
477 Actual_Socket s
= (Actual_Socket
) sock
;
486 * The function which tries to send on a socket once it's deemed
489 void try_send(Actual_Socket s
) {
495 if (s
->sending_oob
) {
496 urgentflag
= MSG_OOB
;
497 len
= s
->sending_oob
;
500 len
= s
->head
->buflen
- s
->head
->bufpos
;
503 nsent
= send(s
->s
, s
->head
->buf
+ s
->head
->bufpos
, len
, urgentflag
);
504 noise_ultralight(nsent
);
506 err
= (nsent
< 0 ?
WSAGetLastError() : 0);
507 if (err
== WSAEWOULDBLOCK
) {
508 /* Perfectly normal: we've sent all we can for the moment. */
511 } else if (nsent
== 0 ||
512 err
== WSAECONNABORTED
||
513 err
== WSAECONNRESET
) {
515 * FIXME. This will have to be done better when we
516 * start managing multiple sockets (e.g. SSH port
517 * forwarding), because if we get CONNRESET while
518 * trying to write a particular forwarded socket
519 * then it isn't necessarily the end of the world.
520 * Ideally I'd like to pass the error code back to
521 * somewhere the next select_result() will see it,
522 * but that might be hard. Perhaps I should pass it
523 * back to be queued in the Windows front end bit.
525 fatalbox(winsock_error_string(err
));
527 fatalbox(winsock_error_string(err
));
530 s
->head
->bufpos
+= nsent
;
532 s
->sending_oob
-= nsent
;
533 if (s
->head
->bufpos
>= s
->head
->buflen
) {
534 struct buffer
*tmp
= s
->head
;
544 static void sk_tcp_write(Socket sock
, char *buf
, int len
) {
545 Actual_Socket s
= (Actual_Socket
) sock
;
548 * Add the data to the buffer list on the socket.
550 if (s
->tail
&& s
->tail
->buflen
< BUFFER_GRANULE
) {
551 int copylen
= min(len
, BUFFER_GRANULE
- s
->tail
->buflen
);
552 memcpy(s
->tail
->buf
+ s
->tail
->buflen
, buf
, copylen
);
555 s
->tail
->buflen
+= copylen
;
558 int grainlen
= min(len
, BUFFER_GRANULE
);
559 struct buffer
*newbuf
;
560 newbuf
= smalloc(sizeof(struct buffer
));
562 newbuf
->buflen
= grainlen
;
563 memcpy(newbuf
->buf
, buf
, grainlen
);
567 s
->tail
->next
= newbuf
;
569 s
->head
= s
->tail
= newbuf
;
575 * Now try sending from the start of the buffer list.
581 static void sk_tcp_write_oob(Socket sock
, char *buf
, int len
) {
582 Actual_Socket s
= (Actual_Socket
) sock
;
585 * Replace the buffer list on the socket with the data.
588 s
->head
= smalloc(sizeof(struct buffer
));
590 struct buffer
*walk
= s
->head
->next
;
592 struct buffer
*tmp
= walk
;
597 s
->head
->next
= NULL
;
599 s
->head
->buflen
= len
;
600 memcpy(s
->head
->buf
, buf
, len
);
603 * Set the Urgent marker.
605 s
->sending_oob
= len
;
608 * Now try sending from the start of the buffer list.
614 int select_result(WPARAM wParam
, LPARAM lParam
) {
617 char buf
[BUFFER_GRANULE
];
621 /* wParam is the socket itself */
622 s
= find234(sktree
, (void *)wParam
, cmpforsearch
);
624 return 1; /* boggle */
626 if ((err
= WSAGETSELECTERROR(lParam
)) != 0) {
628 * An error has occurred on this socket. Pass it to the
631 return plug_closing (s
->plug
, winsock_error_string(err
), err
, 0);
634 noise_ultralight(lParam
);
636 switch (WSAGETSELECTEVENT(lParam
)) {
639 * We have received data on the socket. For an oobinline
640 * socket, this might be data _before_ an urgent pointer,
641 * in which case we send it to the back end with type==1
642 * (data prior to urgent).
646 ioctlsocket(s
->s
, SIOCATMARK
, &atmark
);
648 * Avoid checking the return value from ioctlsocket(),
649 * on the grounds that some WinSock wrappers don't
650 * support it. If it does nothing, we get atmark==1,
651 * which is equivalent to `no OOB pending', so the
652 * effect will be to non-OOB-ify any OOB data.
657 ret
= recv(s
->s
, buf
, sizeof(buf
), 0);
658 noise_ultralight(ret
);
660 err
= WSAGetLastError();
661 if (err
== WSAEWOULDBLOCK
) {
666 return plug_closing (s
->plug
, winsock_error_string(err
), err
, 0);
667 } else if (0 == ret
) {
668 return plug_closing (s
->plug
, NULL
, 0, 0);
670 return plug_receive (s
->plug
, atmark ?
0 : 1, buf
, ret
);
675 * This will only happen on a non-oobinline socket. It
676 * indicates that we can immediately perform an OOB read
677 * and get back OOB data, which we will send to the back
678 * end with type==2 (urgent data).
680 ret
= recv(s
->s
, buf
, sizeof(buf
), MSG_OOB
);
681 noise_ultralight(ret
);
683 fatalbox(ret
== 0 ?
"Internal networking trouble" :
684 winsock_error_string(WSAGetLastError()));
686 return plug_receive (s
->plug
, 2, buf
, ret
);
694 /* Signal a close on the socket. First read any outstanding data. */
697 ret
= recv(s
->s
, buf
, sizeof(buf
), 0);
699 err
= WSAGetLastError();
700 if (err
== WSAEWOULDBLOCK
)
702 return plug_closing (s
->plug
, winsock_error_string(err
), err
, 0);
704 if (ret
) open
&= plug_receive (s
->plug
, 0, buf
, ret
);
705 else open
&= plug_closing (s
->plug
, NULL
, 0, 0);
715 * Each socket abstraction contains a `void *' private field in
716 * which the client can keep state.
718 void sk_set_private_ptr(Socket sock
, void *ptr
) {
719 Actual_Socket s
= (Actual_Socket
) sock
;
720 s
->private_ptr
= ptr
;
722 void *sk_get_private_ptr(Socket sock
) {
723 Actual_Socket s
= (Actual_Socket
) sock
;
724 return s
->private_ptr
;
728 * Special error values are returned from sk_namelookup and sk_new
729 * if there's a problem. These functions extract an error message,
730 * or return NULL if there's no problem.
732 char *sk_addr_error(SockAddr addr
) {
735 static char *sk_tcp_socket_error(Socket sock
) {
736 Actual_Socket s
= (Actual_Socket
) sock
;
741 * For Plink: enumerate all sockets currently active.
743 SOCKET
first_socket(enum234
*e
) {
744 Actual_Socket s
= first234(sktree
, e
);
745 return s ? s
->s
: INVALID_SOCKET
;
747 SOCKET
next_socket(enum234
*e
) {
748 Actual_Socket s
= next234(e
);
749 return s ? s
->s
: INVALID_SOCKET
;