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 char *winsock_error_string(int 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";
100 SockAddr sk_namelookup(char *host, char **canonicalname) {
101 SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
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);
111 memcpy (&a, h->h_addr, sizeof(a));
112 *canonicalname = h->h_name;
115 *canonicalname = host;
117 ret->address = ntohl(a);
122 void sk_addr_free(SockAddr addr) {
126 Socket sk_new(SockAddr addr, int port, sk_receiver_t receiver) {
132 extern char *do_select(SOCKET skt, int startup);
135 * Create Socket structure.
137 ret = smalloc(sizeof(struct Socket_tag));
139 ret->receiver = receiver;
140 ret->head = ret->tail = NULL;
141 ret->writable = 1; /* to start with */
143 ret->sending_oob = 0;
148 s = socket(AF_INET, SOCK_STREAM, 0);
151 if (s == INVALID_SOCKET) {
152 err = WSAGetLastError();
153 ret->error = winsock_error_string(err);
158 * Bind to local address.
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);
170 * Connect to remote address.
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);
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);
193 void sk_close(Socket s) {
201 * The function which tries to send on a socket once it's deemed
204 void try_send(Socket s) {
210 if (s->sending_oob) {
211 urgentflag = MSG_OOB;
212 len = s->sending_oob;
215 len = s->head->buflen - s->head->bufpos;
218 nsent = send(s->s, s->head->buf + s->head->bufpos, len, urgentflag);
219 noise_ultralight(nsent);
221 err = (nsent < 0 ? WSAGetLastError() : 0);
222 if (err == WSAEWOULDBLOCK) {
223 /* Perfectly normal: we've sent all we can for the moment. */
226 } else if (nsent == 0 ||
227 err == WSAECONNABORTED ||
228 err == WSAECONNRESET) {
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.
240 fatalbox(winsock_error_string(err));
242 fatalbox(winsock_error_string(err));
245 s->head->bufpos += nsent;
247 s->sending_oob -= nsent;
248 if (s->head->bufpos >= s->head->buflen) {
249 struct buffer *tmp = s->head;
259 void sk_write(Socket s, char *buf, int len) {
261 * Add the data to the buffer list on the socket.
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);
268 s->tail->buflen += copylen;
271 int grainlen = min(len, BUFFER_GRANULE);
272 struct buffer *newbuf;
273 newbuf = smalloc(sizeof(struct buffer));
275 newbuf->buflen = grainlen;
276 memcpy(newbuf->buf, buf, grainlen);
280 s->tail->next = newbuf;
282 s->head = s->tail = newbuf;
288 * Now try sending from the start of the buffer list.
294 void sk_write_oob(Socket s, char *buf, int len) {
296 * Replace the buffer list on the socket with the data.
299 s->head = smalloc(sizeof(struct buffer));
301 struct buffer *walk = s->head->next;
303 struct buffer *tmp = walk;
308 s->head->next = NULL;
310 s->head->buflen = len;
311 memcpy(s->head->buf, buf, len);
314 * Set the Urgent marker.
316 s->sending_oob = len;
319 * Now try sending from the start of the buffer list.
325 int select_result(WPARAM wParam, LPARAM lParam) {
328 char buf[BUFFER_GRANULE];
332 /* wParam is the socket itself */
333 s = find234(sktree, (void *)wParam, cmpforsearch);
335 return 1; /* boggle */
337 if ((err = WSAGETSELECTERROR(lParam)) != 0) {
338 fatalbox(winsock_error_string(err));
341 noise_ultralight(lParam);
343 switch (WSAGETSELECTEVENT(lParam)) {
345 ret = recv(s->s, buf, sizeof(buf), 0);
347 err = WSAGetLastError();
348 if (err == WSAEWOULDBLOCK) {
353 fatalbox(winsock_error_string(err));
355 int type = s->in_oob ? 2 : 0;
357 return s->receiver(s, type, buf, ret);
362 * Read all data up to the OOB marker, and send it to the
363 * receiver with urgent==1 (OOB pending).
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);
375 fatalbox(ret == 0 ? "Internal networking trouble" :
376 winsock_error_string(WSAGetLastError()));
378 return s->receiver(s, atmark ? 2 : 1, buf, ret);
386 /* Signal a close on the socket. */
387 return s->receiver(s, 0, NULL, 0);
395 * Each socket abstraction contains a `void *' private field in
396 * which the client can keep state.
398 void sk_set_private_ptr(Socket s, void *ptr) {
399 s->private_ptr = ptr;
401 void *sk_get_private_ptr(Socket s) {
402 return s->private_ptr;
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.
410 char *sk_addr_error(SockAddr addr) {
413 char *sk_socket_error(Socket s) {
418 * For Plink: enumerate all sockets currently active.
420 SOCKET first_socket(enum234 *e) {
421 Socket s = first234(sktree, e);
422 return s ? s->s : INVALID_SOCKET;
424 SOCKET next_socket(enum234 *e) {
425 Socket s = next234(e);
426 return s ? s->s : INVALID_SOCKET;