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