e36d9e16178bb02e8d500d92ccd74bcc50d714d8
[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 #include <stdlib.h>
9
10 #include "putty.h"
11 #include "network.h"
12 #include "tree234.h"
13
14 #define BUFFER_GRANULE 512
15
16 struct Socket_tag {
17 char *error;
18 SOCKET s;
19 sk_receiver_t receiver;
20 void *private_ptr;
21 struct buffer *head, *tail;
22 int writable;
23 int in_oob, sending_oob;
24 };
25
26 struct SockAddr_tag {
27 char *error;
28 unsigned long address;
29 };
30
31 struct buffer {
32 struct buffer *next;
33 int buflen, bufpos;
34 char buf[BUFFER_GRANULE];
35 };
36
37 static tree234 *sktree;
38
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;
44 return 0;
45 }
46
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;
52 return 0;
53 }
54
55 void sk_init(void) {
56 sktree = newtree234(cmpfortree);
57 }
58
59 SockAddr sk_namelookup(char *host, char **canonicalname) {
60 SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
61 unsigned long a;
62 struct hostent *h;
63
64 ret->error = NULL;
65 if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) {
66 if ( (h = gethostbyname(host)) == NULL) {
67 DWORD err = WSAGetLastError();
68 ret->error = (err == WSAENETDOWN ? "Network is down" :
69 err == WSAHOST_NOT_FOUND ? "Host does not exist" :
70 err == WSATRY_AGAIN ? "Host not found" :
71 "gethostbyname: unknown error");
72 } else {
73 memcpy (&a, h->h_addr, sizeof(a));
74 *canonicalname = h->h_name;
75 }
76 } else {
77 *canonicalname = host;
78 }
79 ret->address = ntohl(a);
80
81 return ret;
82 }
83
84 void sk_addr_free(SockAddr addr) {
85 sfree(addr);
86 }
87
88 Socket sk_new(SockAddr addr, int port, sk_receiver_t receiver) {
89 SOCKET s;
90 SOCKADDR_IN a;
91 DWORD err;
92 char *errstr;
93 Socket ret;
94 extern char *do_select(SOCKET skt, int startup);
95
96 /*
97 * Create Socket structure.
98 */
99 ret = smalloc(sizeof(struct Socket_tag));
100 ret->error = NULL;
101 ret->receiver = receiver;
102 ret->head = ret->tail = NULL;
103 ret->writable = 1; /* to start with */
104 ret->in_oob = FALSE;
105 ret->sending_oob = 0;
106
107 /*
108 * Open socket.
109 */
110 s = socket(AF_INET, SOCK_STREAM, 0);
111 ret->s = s;
112
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");
118 return ret;
119 }
120
121 /*
122 * Bind to local address.
123 */
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");
131 return ret;
132 }
133
134 /*
135 * Connect to remote address.
136 */
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");
146 return ret;
147 }
148
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);
152 if (errstr) {
153 ret->error = errstr;
154 return ret;
155 }
156
157 add234(sktree, ret);
158
159 return ret;
160 }
161
162 void sk_close(Socket s) {
163 del234(sktree, s);
164 do_select(s->s, 0);
165 closesocket(s->s);
166 free(s);
167 }
168
169 char *winsock_error_string(int error) {
170 switch (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";
207 }
208 }
209
210 /*
211 * The function which tries to send on a socket once it's deemed
212 * writable.
213 */
214 void try_send(Socket s) {
215 while (s->head) {
216 int nsent;
217 DWORD err;
218 int len, urgentflag;
219
220 if (s->sending_oob) {
221 urgentflag = MSG_OOB;
222 len = s->sending_oob;
223 } else {
224 urgentflag = 0;
225 len = s->head->buflen - s->head->bufpos;
226 }
227
228 nsent = send(s->s, s->head->buf + s->head->bufpos, len, urgentflag);
229 noise_ultralight(nsent);
230 if (nsent <= 0) {
231 err = (nsent < 0 ? WSAGetLastError() : 0);
232 if (err == WSAEWOULDBLOCK) {
233 /* Perfectly normal: we've sent all we can for the moment. */
234 s->writable = FALSE;
235 return;
236 } else if (nsent == 0 ||
237 err == WSAECONNABORTED ||
238 err == WSAECONNRESET) {
239 /*
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.
249 */
250 fatalbox(winsock_error_string(err));
251 } else {
252 fatalbox(winsock_error_string(err));
253 }
254 } else {
255 s->head->bufpos += nsent;
256 if (s->sending_oob)
257 s->sending_oob -= nsent;
258 if (s->head->bufpos >= s->head->buflen) {
259 struct buffer *tmp = s->head;
260 s->head = tmp->next;
261 free(tmp);
262 if (!s->head)
263 s->tail = NULL;
264 }
265 }
266 }
267 }
268
269 void sk_write(Socket s, char *buf, int len) {
270 /*
271 * Add the data to the buffer list on the socket.
272 */
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);
276 buf += copylen;
277 len -= copylen;
278 s->tail->buflen += copylen;
279 }
280 while (len > 0) {
281 int grainlen = min(len, BUFFER_GRANULE);
282 struct buffer *newbuf;
283 newbuf = smalloc(sizeof(struct buffer));
284 newbuf->bufpos = 0;
285 newbuf->buflen = grainlen;
286 memcpy(newbuf->buf, buf, grainlen);
287 buf += grainlen;
288 len -= grainlen;
289 if (s->tail)
290 s->tail->next = newbuf;
291 else
292 s->head = s->tail = newbuf;
293 newbuf->next = NULL;
294 s->tail = newbuf;
295 }
296
297 /*
298 * Now try sending from the start of the buffer list.
299 */
300 if (s->writable)
301 try_send(s);
302 }
303
304 void sk_write_oob(Socket s, char *buf, int len) {
305 /*
306 * Replace the buffer list on the socket with the data.
307 */
308 if (!s->head) {
309 s->head = smalloc(sizeof(struct buffer));
310 } else {
311 struct buffer *walk = s->head->next;
312 while (walk) {
313 struct buffer *tmp = walk;
314 walk = tmp->next;
315 free(tmp);
316 }
317 }
318 s->head->next = NULL;
319 s->tail = s->head;
320 s->head->buflen = len;
321 memcpy(s->head->buf, buf, len);
322
323 /*
324 * Set the Urgent marker.
325 */
326 s->sending_oob = len;
327
328 /*
329 * Now try sending from the start of the buffer list.
330 */
331 if (s->writable)
332 try_send(s);
333 }
334
335 int select_result(WPARAM wParam, LPARAM lParam) {
336 int ret;
337 DWORD err;
338 char buf[BUFFER_GRANULE];
339 Socket s;
340 u_long atmark;
341
342 /* wParam is the socket itself */
343 s = find234(sktree, (void *)wParam, cmpforsearch);
344 if (!s)
345 return 1; /* boggle */
346
347 if ((err = WSAGETSELECTERROR(lParam)) != 0) {
348 fatalbox(winsock_error_string(err));
349 }
350
351 noise_ultralight(lParam);
352
353 switch (WSAGETSELECTEVENT(lParam)) {
354 case FD_READ:
355 ret = recv(s->s, buf, sizeof(buf), 0);
356 if (ret < 0) {
357 err = WSAGetLastError();
358 if (err == WSAEWOULDBLOCK) {
359 break;
360 }
361 }
362 if (ret < 0) {
363 fatalbox(winsock_error_string(err));
364 } else {
365 int type = s->in_oob ? 2 : 0;
366 s->in_oob = FALSE;
367 return s->receiver(s, type, buf, ret);
368 }
369 break;
370 case FD_OOB:
371 /*
372 * Read all data up to the OOB marker, and send it to the
373 * receiver with urgent==1 (OOB pending).
374 */
375 atmark = 1;
376 s->in_oob = TRUE;
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);
384 if (ret <= 0) {
385 fatalbox(ret == 0 ? "Internal networking trouble" :
386 winsock_error_string(WSAGetLastError()));
387 } else {
388 return s->receiver(s, atmark ? 2 : 1, buf, ret);
389 }
390 break;
391 case FD_WRITE:
392 s->writable = 1;
393 try_send(s);
394 break;
395 case FD_CLOSE:
396 /* Signal a close on the socket. */
397 return s->receiver(s, 0, NULL, 0);
398 break;
399 }
400
401 return 1;
402 }
403
404 /*
405 * Each socket abstraction contains a `void *' private field in
406 * which the client can keep state.
407 */
408 void sk_set_private_ptr(Socket s, void *ptr) {
409 s->private_ptr = ptr;
410 }
411 void *sk_get_private_ptr(Socket s) {
412 return s->private_ptr;
413 }
414
415 /*
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.
419 */
420 char *sk_addr_error(SockAddr addr) {
421 return addr->error;
422 }
423 char *sk_socket_error(Socket s) {
424 return s->error;
425 }
426
427 /*
428 * For Plink: enumerate all sockets currently active.
429 */
430 SOCKET first_socket(enum234 *e) {
431 Socket s = first234(sktree, e);
432 return s ? s->s : INVALID_SOCKET;
433 }
434 SOCKET next_socket(enum234 *e) {
435 Socket s = next234(e);
436 return s ? s->s : INVALID_SOCKET;
437 }