Improved entropy gathering.
[u/mdw/putty] / winnet.c
1 /*
2 * Windows networking abstraction.
3 */
4
5 #include <windows.h>
6 #include <winsock.h>
7 #include <stdio.h>
8
9 #include "putty.h"
10 #include "network.h"
11 #include "tree234.h"
12
13 #define BUFFER_GRANULE 512
14
15 struct Socket_tag {
16 char *error;
17 SOCKET s;
18 sk_receiver_t receiver;
19 void *private_ptr;
20 struct buffer *head, *tail;
21 int writable;
22 int in_oob, sending_oob;
23 };
24
25 struct SockAddr_tag {
26 char *error;
27 unsigned long address;
28 };
29
30 struct buffer {
31 struct buffer *next;
32 int buflen, bufpos;
33 char buf[BUFFER_GRANULE];
34 };
35
36 static tree234 *sktree;
37
38 static int cmpfortree(void *av, void *bv) {
39 Socket a = (Socket)av, b = (Socket)bv;
40 unsigned long as = (unsigned long)a->s, bs = (unsigned long)b->s;
41 if (as < bs) return -1;
42 if (as > bs) return +1;
43 return 0;
44 }
45
46 static int cmpforsearch(void *av, void *bv) {
47 Socket b = (Socket)bv;
48 unsigned long as = (unsigned long)av, bs = (unsigned long)b->s;
49 if (as < bs) return -1;
50 if (as > bs) return +1;
51 return 0;
52 }
53
54 void sk_init(void) {
55 sktree = newtree234(cmpfortree);
56 }
57
58 SockAddr sk_namelookup(char *host, char **canonicalname) {
59 SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
60 unsigned long a;
61 struct hostent *h;
62
63 if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) {
64 if ( (h = gethostbyname(host)) == NULL) {
65 DWORD err = WSAGetLastError();
66 ret->error = (err == WSAENETDOWN ? "Network is down" :
67 err == WSAHOST_NOT_FOUND ? "Host does not exist" :
68 err == WSATRY_AGAIN ? "Host not found" :
69 "gethostbyname: unknown error");
70 } else {
71 ret->error = NULL;
72 memcpy (&a, h->h_addr, sizeof(a));
73 *canonicalname = h->h_name;
74 }
75 } else {
76 *canonicalname = host;
77 }
78 ret->address = ntohl(a);
79
80 return ret;
81 }
82
83 void sk_addr_free(SockAddr addr) {
84 sfree(addr);
85 }
86
87 Socket sk_new(SockAddr addr, int port, sk_receiver_t receiver) {
88 SOCKET s;
89 SOCKADDR_IN a;
90 DWORD err;
91 char *errstr;
92 Socket ret;
93 extern char *do_select(SOCKET skt, int startup);
94
95 /*
96 * Create Socket structure.
97 */
98 ret = smalloc(sizeof(struct Socket_tag));
99 ret->error = NULL;
100 ret->receiver = receiver;
101 ret->head = ret->tail = NULL;
102 ret->writable = 1; /* to start with */
103 ret->in_oob = FALSE;
104 ret->sending_oob = 0;
105
106 /*
107 * Open socket.
108 */
109 s = socket(AF_INET, SOCK_STREAM, 0);
110 ret->s = s;
111
112 if (s == INVALID_SOCKET) {
113 err = WSAGetLastError();
114 ret->error = (err == WSAENETDOWN ? "Network is down" :
115 err == WSAEAFNOSUPPORT ? "TCP/IP support not present" :
116 "socket(): unknown error");
117 return ret;
118 }
119
120 /*
121 * Bind to local address.
122 */
123 a.sin_family = AF_INET;
124 a.sin_addr.s_addr = htonl(INADDR_ANY);
125 a.sin_port = htons(0);
126 if (bind (s, (struct sockaddr *)&a, sizeof(a)) == SOCKET_ERROR) {
127 err = WSAGetLastError();
128 ret->error = (err == WSAENETDOWN ? "Network is down" :
129 "bind(): unknown error");
130 return ret;
131 }
132
133 /*
134 * Connect to remote address.
135 */
136 a.sin_addr.s_addr = htonl(addr->address);
137 a.sin_port = htons((short)port);
138 if (connect (s, (struct sockaddr *)&a, sizeof(a)) == SOCKET_ERROR) {
139 err = WSAGetLastError();
140 ret->error = (err == WSAENETDOWN ? "Network is down" :
141 err == WSAECONNREFUSED ? "Connection refused" :
142 err == WSAENETUNREACH ? "Network is unreachable" :
143 err == WSAEHOSTUNREACH ? "No route to host" :
144 "connect(): unknown error");
145 return ret;
146 }
147
148 /* Set up a select mechanism. This could be an AsyncSelect on a
149 * window, or an EventSelect on an event object. */
150 errstr = do_select(s, 1);
151 if (errstr) {
152 ret->error = errstr;
153 return ret;
154 }
155
156 add234(sktree, ret);
157
158 return ret;
159 }
160
161 void sk_close(Socket s) {
162 del234(sktree, s);
163 do_select(s->s, 0);
164 closesocket(s->s);
165 free(s);
166 }
167
168 char *winsock_error_string(int error) {
169 switch (error) {
170 case WSAEACCES: return "Network error: Permission denied";
171 case WSAEADDRINUSE: return "Network error: Address already in use";
172 case WSAEADDRNOTAVAIL: return "Network error: Cannot assign requested address";
173 case WSAEAFNOSUPPORT: return "Network error: Address family not supported by protocol family";
174 case WSAEALREADY: return "Network error: Operation already in progress";
175 case WSAECONNABORTED: return "Network error: Software caused connection abort";
176 case WSAECONNREFUSED: return "Network error: Connection refused";
177 case WSAECONNRESET: return "Network error: Connection reset by peer";
178 case WSAEDESTADDRREQ: return "Network error: Destination address required";
179 case WSAEFAULT: return "Network error: Bad address";
180 case WSAEHOSTDOWN: return "Network error: Host is down";
181 case WSAEHOSTUNREACH: return "Network error: No route to host";
182 case WSAEINPROGRESS: return "Network error: Operation now in progress";
183 case WSAEINTR: return "Network error: Interrupted function call";
184 case WSAEINVAL: return "Network error: Invalid argument";
185 case WSAEISCONN: return "Network error: Socket is already connected";
186 case WSAEMFILE: return "Network error: Too many open files";
187 case WSAEMSGSIZE: return "Network error: Message too long";
188 case WSAENETDOWN: return "Network error: Network is down";
189 case WSAENETRESET: return "Network error: Network dropped connection on reset";
190 case WSAENETUNREACH: return "Network error: Network is unreachable";
191 case WSAENOBUFS: return "Network error: No buffer space available";
192 case WSAENOPROTOOPT: return "Network error: Bad protocol option";
193 case WSAENOTCONN: return "Network error: Socket is not connected";
194 case WSAENOTSOCK: return "Network error: Socket operation on non-socket";
195 case WSAEOPNOTSUPP: return "Network error: Operation not supported";
196 case WSAEPFNOSUPPORT: return "Network error: Protocol family not supported";
197 case WSAEPROCLIM: return "Network error: Too many processes";
198 case WSAEPROTONOSUPPORT: return "Network error: Protocol not supported";
199 case WSAEPROTOTYPE: return "Network error: Protocol wrong type for socket";
200 case WSAESHUTDOWN: return "Network error: Cannot send after socket shutdown";
201 case WSAESOCKTNOSUPPORT: return "Network error: Socket type not supported";
202 case WSAETIMEDOUT: return "Network error: Connection timed out";
203 case WSAEWOULDBLOCK: return "Network error: Resource temporarily unavailable";
204 case WSAEDISCON: return "Network error: Graceful shutdown in progress";
205 default: return "Unknown network error";
206 }
207 }
208
209 /*
210 * The function which tries to send on a socket once it's deemed
211 * writable.
212 */
213 void try_send(Socket s) {
214 while (s->head) {
215 int nsent;
216 DWORD err;
217 int len, urgentflag;
218
219 if (s->sending_oob) {
220 urgentflag = MSG_OOB;
221 len = s->sending_oob;
222 } else {
223 urgentflag = 0;
224 len = s->head->buflen - s->head->bufpos;
225 }
226
227 nsent = send(s->s, s->head->buf + s->head->bufpos, len, urgentflag);
228 noise_ultralight(nsent);
229 if (nsent <= 0) {
230 err = (nsent < 0 ? WSAGetLastError() : 0);
231 if (err == WSAEWOULDBLOCK) {
232 /* Perfectly normal: we've sent all we can for the moment. */
233 s->writable = FALSE;
234 return;
235 } else if (nsent == 0 ||
236 err == WSAECONNABORTED ||
237 err == WSAECONNRESET) {
238 /*
239 * FIXME. This will have to be done better when we
240 * start managing multiple sockets (e.g. SSH port
241 * forwarding), because if we get CONNRESET while
242 * trying to write a particular forwarded socket
243 * then it isn't necessarily the end of the world.
244 * Ideally I'd like to pass the error code back to
245 * somewhere the next select_result() will see it,
246 * but that might be hard. Perhaps I should pass it
247 * back to be queued in the Windows front end bit.
248 */
249 fatalbox(winsock_error_string(err));
250 } else {
251 fatalbox(winsock_error_string(err));
252 }
253 } else {
254 s->head->bufpos += nsent;
255 if (s->sending_oob)
256 s->sending_oob -= nsent;
257 if (s->head->bufpos >= s->head->buflen) {
258 struct buffer *tmp = s->head;
259 s->head = tmp->next;
260 free(tmp);
261 if (!s->head)
262 s->tail = NULL;
263 }
264 }
265 }
266 }
267
268 void sk_write(Socket s, char *buf, int len) {
269 /*
270 * Add the data to the buffer list on the socket.
271 */
272 if (s->tail && s->tail->buflen < BUFFER_GRANULE) {
273 int copylen = min(len, BUFFER_GRANULE - s->tail->buflen);
274 memcpy(s->tail->buf + s->tail->buflen, buf, copylen);
275 buf += copylen;
276 len -= copylen;
277 s->tail->buflen += copylen;
278 }
279 while (len > 0) {
280 int grainlen = min(len, BUFFER_GRANULE);
281 struct buffer *newbuf;
282 newbuf = smalloc(sizeof(struct buffer));
283 newbuf->bufpos = 0;
284 newbuf->buflen = grainlen;
285 memcpy(newbuf->buf, buf, grainlen);
286 buf += grainlen;
287 len -= grainlen;
288 if (s->tail)
289 s->tail->next = newbuf;
290 else
291 s->head = s->tail = newbuf;
292 newbuf->next = NULL;
293 s->tail = newbuf;
294 }
295
296 /*
297 * Now try sending from the start of the buffer list.
298 */
299 if (s->writable)
300 try_send(s);
301 }
302
303 void sk_write_oob(Socket s, char *buf, int len) {
304 /*
305 * Replace the buffer list on the socket with the data.
306 */
307 if (!s->head) {
308 s->head = smalloc(sizeof(struct buffer));
309 } else {
310 struct buffer *walk = s->head->next;
311 while (walk) {
312 struct buffer *tmp = walk;
313 walk = tmp->next;
314 free(tmp);
315 }
316 }
317 s->head->next = NULL;
318 s->tail = s->head;
319 s->head->buflen = len;
320 memcpy(s->head->buf, buf, len);
321
322 /*
323 * Set the Urgent marker.
324 */
325 s->sending_oob = len;
326
327 /*
328 * Now try sending from the start of the buffer list.
329 */
330 if (s->writable)
331 try_send(s);
332 }
333
334 int select_result(WPARAM wParam, LPARAM lParam) {
335 int ret;
336 DWORD err;
337 char buf[BUFFER_GRANULE];
338 Socket s;
339 int atmark;
340
341 /* wParam is the socket itself */
342 s = find234(sktree, (void *)wParam, cmpforsearch);
343 if (!s)
344 return 1; /* boggle */
345
346 if ((err = WSAGETSELECTERROR(lParam)) != 0) {
347 fatalbox(winsock_error_string(err));
348 }
349
350 noise_ultralight(lParam);
351
352 switch (WSAGETSELECTEVENT(lParam)) {
353 case FD_READ:
354 ret = recv(s->s, buf, sizeof(buf), 0);
355 if (ret < 0) {
356 err = WSAGetLastError();
357 if (err == WSAEWOULDBLOCK) {
358 break;
359 }
360 }
361 if (ret < 0) {
362 fatalbox(winsock_error_string(err));
363 } else {
364 int type = s->in_oob ? 2 : 0;
365 s->in_oob = FALSE;
366 return s->receiver(s, type, buf, ret);
367 }
368 break;
369 case FD_OOB:
370 /*
371 * Read all data up to the OOB marker, and send it to the
372 * receiver with urgent==1 (OOB pending).
373 */
374 atmark = 1;
375 s->in_oob = TRUE;
376 /* Some WinSock wrappers don't support this call, so we
377 * deliberately don't check the return value. If the call
378 * fails and does nothing, we will get back atmark==1,
379 * which is good enough to keep going at least. */
380 ioctlsocket(s->s, SIOCATMARK, &atmark);
381 ret = recv(s->s, buf, sizeof(buf), MSG_OOB);
382 noise_ultralight(ret);
383 if (ret <= 0) {
384 fatalbox(ret == 0 ? "Internal networking trouble" :
385 winsock_error_string(WSAGetLastError()));
386 } else {
387 return s->receiver(s, atmark ? 2 : 1, buf, ret);
388 }
389 break;
390 case FD_WRITE:
391 s->writable = 1;
392 try_send(s);
393 break;
394 case FD_CLOSE:
395 /* Signal a close on the socket. */
396 return s->receiver(s, 0, NULL, 0);
397 break;
398 }
399
400 return 1;
401 }
402
403 /*
404 * Each socket abstraction contains a `void *' private field in
405 * which the client can keep state.
406 */
407 void sk_set_private_ptr(Socket s, void *ptr) {
408 s->private_ptr = ptr;
409 }
410 void *sk_get_private_ptr(Socket s) {
411 return s->private_ptr;
412 }
413
414 /*
415 * Special error values are returned from sk_namelookup and sk_new
416 * if there's a problem. These functions extract an error message,
417 * or return NULL if there's no problem.
418 */
419 char *sk_addr_error(SockAddr addr) {
420 return addr->error;
421 }
422 char *sk_socket_error(Socket s) {
423 return s->error;
424 }
425
426 /*
427 * For Plink: enumerate all sockets currently active.
428 */
429 SOCKET first_socket(enum234 *e) {
430 Socket s = first234(sktree, e);
431 return s ? s->s : INVALID_SOCKET;
432 }
433 SOCKET next_socket(enum234 *e) {
434 Socket s = next234(e);
435 return s ? s->s : INVALID_SOCKET;
436 }