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