2 * Windows networking abstraction.
14 #define BUFFER_GRANULE 512
19 sk_receiver_t receiver
;
21 struct buffer
*head
, *tail
;
23 int in_oob
, sending_oob
;
28 unsigned long address
;
34 char buf
[BUFFER_GRANULE
];
37 static tree234
*sktree
;
39 static int cmpfortree(void *av
, void *bv
) {
40 Socket a
= (Socket
)av
, b
= (Socket
)bv
;
41 unsigned long as
= (unsigned long)a
->s
, bs
= (unsigned long)b
->s
;
42 if (as
< bs
) return -1;
43 if (as
> bs
) return +1;
47 static int cmpforsearch(void *av
, void *bv
) {
48 Socket b
= (Socket
)bv
;
49 unsigned long as
= (unsigned long)av
, bs
= (unsigned long)b
->s
;
50 if (as
< bs
) return -1;
51 if (as
> bs
) return +1;
56 sktree
= newtree234(cmpfortree
);
59 SockAddr
sk_namelookup(char *host
, char **canonicalname
) {
60 SockAddr ret
= smalloc(sizeof(struct SockAddr_tag
));
64 if ( (a
= inet_addr(host
)) == (unsigned long) INADDR_NONE
) {
65 if ( (h
= gethostbyname(host
)) == NULL
) {
66 DWORD err
= WSAGetLastError();
67 ret
->error
= (err
== WSAENETDOWN ?
"Network is down" :
68 err
== WSAHOST_NOT_FOUND ?
"Host does not exist" :
69 err
== WSATRY_AGAIN ?
"Host not found" :
70 "gethostbyname: unknown error");
73 memcpy (&a
, h
->h_addr
, sizeof(a
));
74 *canonicalname
= h
->h_name
;
77 *canonicalname
= host
;
79 ret
->address
= ntohl(a
);
84 void sk_addr_free(SockAddr addr
) {
88 Socket
sk_new(SockAddr addr
, int port
, sk_receiver_t receiver
) {
94 extern char *do_select(SOCKET skt
, int startup
);
97 * Create Socket structure.
99 ret
= smalloc(sizeof(struct Socket_tag
));
101 ret
->receiver
= receiver
;
102 ret
->head
= ret
->tail
= NULL
;
103 ret
->writable
= 1; /* to start with */
105 ret
->sending_oob
= 0;
110 s
= socket(AF_INET
, SOCK_STREAM
, 0);
113 if (s
== INVALID_SOCKET
) {
114 err
= WSAGetLastError();
115 ret
->error
= (err
== WSAENETDOWN ?
"Network is down" :
116 err
== WSAEAFNOSUPPORT ?
"TCP/IP support not present" :
117 "socket(): unknown error");
122 * Bind to local address.
124 a
.sin_family
= AF_INET
;
125 a
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
126 a
.sin_port
= htons(0);
127 if (bind (s
, (struct sockaddr
*)&a
, sizeof(a
)) == SOCKET_ERROR
) {
128 err
= WSAGetLastError();
129 ret
->error
= (err
== WSAENETDOWN ?
"Network is down" :
130 "bind(): unknown error");
135 * Connect to remote address.
137 a
.sin_addr
.s_addr
= htonl(addr
->address
);
138 a
.sin_port
= htons((short)port
);
139 if (connect (s
, (struct sockaddr
*)&a
, sizeof(a
)) == SOCKET_ERROR
) {
140 err
= WSAGetLastError();
141 ret
->error
= (err
== WSAENETDOWN ?
"Network is down" :
142 err
== WSAECONNREFUSED ?
"Connection refused" :
143 err
== WSAENETUNREACH ?
"Network is unreachable" :
144 err
== WSAEHOSTUNREACH ?
"No route to host" :
145 "connect(): unknown error");
149 /* Set up a select mechanism. This could be an AsyncSelect on a
150 * window, or an EventSelect on an event object. */
151 errstr
= do_select(s
, 1);
162 void sk_close(Socket s
) {
169 char *winsock_error_string(int error
) {
171 case WSAEACCES
: return "Network error: Permission denied";
172 case WSAEADDRINUSE
: return "Network error: Address already in use";
173 case WSAEADDRNOTAVAIL
: return "Network error: Cannot assign requested address";
174 case WSAEAFNOSUPPORT
: return "Network error: Address family not supported by protocol family";
175 case WSAEALREADY
: return "Network error: Operation already in progress";
176 case WSAECONNABORTED
: return "Network error: Software caused connection abort";
177 case WSAECONNREFUSED
: return "Network error: Connection refused";
178 case WSAECONNRESET
: return "Network error: Connection reset by peer";
179 case WSAEDESTADDRREQ
: return "Network error: Destination address required";
180 case WSAEFAULT
: return "Network error: Bad address";
181 case WSAEHOSTDOWN
: return "Network error: Host is down";
182 case WSAEHOSTUNREACH
: return "Network error: No route to host";
183 case WSAEINPROGRESS
: return "Network error: Operation now in progress";
184 case WSAEINTR
: return "Network error: Interrupted function call";
185 case WSAEINVAL
: return "Network error: Invalid argument";
186 case WSAEISCONN
: return "Network error: Socket is already connected";
187 case WSAEMFILE
: return "Network error: Too many open files";
188 case WSAEMSGSIZE
: return "Network error: Message too long";
189 case WSAENETDOWN
: return "Network error: Network is down";
190 case WSAENETRESET
: return "Network error: Network dropped connection on reset";
191 case WSAENETUNREACH
: return "Network error: Network is unreachable";
192 case WSAENOBUFS
: return "Network error: No buffer space available";
193 case WSAENOPROTOOPT
: return "Network error: Bad protocol option";
194 case WSAENOTCONN
: return "Network error: Socket is not connected";
195 case WSAENOTSOCK
: return "Network error: Socket operation on non-socket";
196 case WSAEOPNOTSUPP
: return "Network error: Operation not supported";
197 case WSAEPFNOSUPPORT
: return "Network error: Protocol family not supported";
198 case WSAEPROCLIM
: return "Network error: Too many processes";
199 case WSAEPROTONOSUPPORT
: return "Network error: Protocol not supported";
200 case WSAEPROTOTYPE
: return "Network error: Protocol wrong type for socket";
201 case WSAESHUTDOWN
: return "Network error: Cannot send after socket shutdown";
202 case WSAESOCKTNOSUPPORT
: return "Network error: Socket type not supported";
203 case WSAETIMEDOUT
: return "Network error: Connection timed out";
204 case WSAEWOULDBLOCK
: return "Network error: Resource temporarily unavailable";
205 case WSAEDISCON
: return "Network error: Graceful shutdown in progress";
206 default: return "Unknown network error";
211 * The function which tries to send on a socket once it's deemed
214 void try_send(Socket s
) {
220 if (s
->sending_oob
) {
221 urgentflag
= MSG_OOB
;
222 len
= s
->sending_oob
;
225 len
= s
->head
->buflen
- s
->head
->bufpos
;
228 nsent
= send(s
->s
, s
->head
->buf
+ s
->head
->bufpos
, len
, urgentflag
);
229 noise_ultralight(nsent
);
231 err
= (nsent
< 0 ?
WSAGetLastError() : 0);
232 if (err
== WSAEWOULDBLOCK
) {
233 /* Perfectly normal: we've sent all we can for the moment. */
236 } else if (nsent
== 0 ||
237 err
== WSAECONNABORTED
||
238 err
== WSAECONNRESET
) {
240 * FIXME. This will have to be done better when we
241 * start managing multiple sockets (e.g. SSH port
242 * forwarding), because if we get CONNRESET while
243 * trying to write a particular forwarded socket
244 * then it isn't necessarily the end of the world.
245 * Ideally I'd like to pass the error code back to
246 * somewhere the next select_result() will see it,
247 * but that might be hard. Perhaps I should pass it
248 * back to be queued in the Windows front end bit.
250 fatalbox(winsock_error_string(err
));
252 fatalbox(winsock_error_string(err
));
255 s
->head
->bufpos
+= nsent
;
257 s
->sending_oob
-= nsent
;
258 if (s
->head
->bufpos
>= s
->head
->buflen
) {
259 struct buffer
*tmp
= s
->head
;
269 void sk_write(Socket s
, char *buf
, int len
) {
271 * Add the data to the buffer list on the socket.
273 if (s
->tail
&& s
->tail
->buflen
< BUFFER_GRANULE
) {
274 int copylen
= min(len
, BUFFER_GRANULE
- s
->tail
->buflen
);
275 memcpy(s
->tail
->buf
+ s
->tail
->buflen
, buf
, copylen
);
278 s
->tail
->buflen
+= copylen
;
281 int grainlen
= min(len
, BUFFER_GRANULE
);
282 struct buffer
*newbuf
;
283 newbuf
= smalloc(sizeof(struct buffer
));
285 newbuf
->buflen
= grainlen
;
286 memcpy(newbuf
->buf
, buf
, grainlen
);
290 s
->tail
->next
= newbuf
;
292 s
->head
= s
->tail
= newbuf
;
298 * Now try sending from the start of the buffer list.
304 void sk_write_oob(Socket s
, char *buf
, int len
) {
306 * Replace the buffer list on the socket with the data.
309 s
->head
= smalloc(sizeof(struct buffer
));
311 struct buffer
*walk
= s
->head
->next
;
313 struct buffer
*tmp
= walk
;
318 s
->head
->next
= NULL
;
320 s
->head
->buflen
= len
;
321 memcpy(s
->head
->buf
, buf
, len
);
324 * Set the Urgent marker.
326 s
->sending_oob
= len
;
329 * Now try sending from the start of the buffer list.
335 int select_result(WPARAM wParam
, LPARAM lParam
) {
338 char buf
[BUFFER_GRANULE
];
342 /* wParam is the socket itself */
343 s
= find234(sktree
, (void *)wParam
, cmpforsearch
);
345 return 1; /* boggle */
347 if ((err
= WSAGETSELECTERROR(lParam
)) != 0) {
348 fatalbox(winsock_error_string(err
));
351 noise_ultralight(lParam
);
353 switch (WSAGETSELECTEVENT(lParam
)) {
355 ret
= recv(s
->s
, buf
, sizeof(buf
), 0);
357 err
= WSAGetLastError();
358 if (err
== WSAEWOULDBLOCK
) {
363 fatalbox(winsock_error_string(err
));
365 int type
= s
->in_oob ?
2 : 0;
367 return s
->receiver(s
, type
, buf
, ret
);
372 * Read all data up to the OOB marker, and send it to the
373 * receiver with urgent==1 (OOB pending).
377 /* Some WinSock wrappers don't support this call, so we
378 * deliberately don't check the return value. If the call
379 * fails and does nothing, we will get back atmark==1,
380 * which is good enough to keep going at least. */
381 ioctlsocket(s
->s
, SIOCATMARK
, &atmark
);
382 ret
= recv(s
->s
, buf
, sizeof(buf
), MSG_OOB
);
383 noise_ultralight(ret
);
385 fatalbox(ret
== 0 ?
"Internal networking trouble" :
386 winsock_error_string(WSAGetLastError()));
388 return s
->receiver(s
, atmark ?
2 : 1, buf
, ret
);
396 /* Signal a close on the socket. */
397 return s
->receiver(s
, 0, NULL
, 0);
405 * Each socket abstraction contains a `void *' private field in
406 * which the client can keep state.
408 void sk_set_private_ptr(Socket s
, void *ptr
) {
409 s
->private_ptr
= ptr
;
411 void *sk_get_private_ptr(Socket s
) {
412 return s
->private_ptr
;
416 * Special error values are returned from sk_namelookup and sk_new
417 * if there's a problem. These functions extract an error message,
418 * or return NULL if there's no problem.
420 char *sk_addr_error(SockAddr addr
) {
423 char *sk_socket_error(Socket s
) {
428 * For Plink: enumerate all sockets currently active.
430 SOCKET
first_socket(enum234
*e
) {
431 Socket s
= first234(sktree
, e
);
432 return s ? s
->s
: INVALID_SOCKET
;
434 SOCKET
next_socket(enum234
*e
) {
435 Socket s
= next234(e
);
436 return s ? s
->s
: INVALID_SOCKET
;