2 * Windows networking abstraction.
13 #define BUFFER_GRANULE 512
18 sk_receiver_t receiver;
20 struct buffer *head, *tail;
22 int in_oob, sending_oob;
27 unsigned long address;
33 char buf[BUFFER_GRANULE];
36 static tree234 *sktree;
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;
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;
55 sktree = newtree234(cmpfortree);
58 SockAddr sk_namelookup(char *host, char **canonicalname) {
59 SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
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");
72 memcpy (&a, h->h_addr, sizeof(a));
73 *canonicalname = h->h_name;
76 *canonicalname = host;
78 ret->address = ntohl(a);
83 void sk_addr_free(SockAddr addr) {
87 Socket sk_new(SockAddr addr, int port, sk_receiver_t receiver) {
93 extern char *do_select(SOCKET skt, int startup);
96 * Create Socket structure.
98 ret = smalloc(sizeof(struct Socket_tag));
100 ret->receiver = receiver;
101 ret->head = ret->tail = NULL;
102 ret->writable = 1; /* to start with */
108 s = socket(AF_INET, SOCK_STREAM, 0);
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");
120 * Bind to local address.
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");
133 * Connect to remote address.
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");
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);
160 void sk_close(Socket s) {
167 char *winsock_error_string(int 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";
209 * The function which tries to send on a socket once it's deemed
212 void try_send(Socket s) {
218 if (s->sending_oob) {
219 urgentflag = MSG_OOB;
220 len = s->sending_oob;
223 len = s->head->buflen - s->head->bufpos;
226 nsent = send(s->s, s->head->buf + s->head->bufpos, len, urgentflag);
228 err = (nsent < 0 ? WSAGetLastError() : 0);
229 if (err == WSAEWOULDBLOCK) {
230 /* Perfectly normal: we've sent all we can for the moment. */
233 } else if (nsent == 0 ||
234 err == WSAECONNABORTED ||
235 err == WSAECONNRESET) {
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.
247 fatalbox(winsock_error_string(err));
249 fatalbox(winsock_error_string(err));
252 s->head->bufpos += nsent;
254 s->sending_oob -= nsent;
255 if (s->head->bufpos >= s->head->buflen) {
256 struct buffer *tmp = s->head;
266 void sk_write(Socket s, char *buf, int len) {
268 * Add the data to the buffer list on the socket.
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);
275 s->tail->buflen += copylen;
278 int grainlen = min(len, BUFFER_GRANULE);
279 struct buffer *newbuf;
280 newbuf = smalloc(sizeof(struct buffer));
282 newbuf->buflen = grainlen;
283 memcpy(newbuf->buf, buf, grainlen);
287 s->tail->next = newbuf;
289 s->head = s->tail = newbuf;
295 * Now try sending from the start of the buffer list.
301 void sk_write_oob(Socket s, char *buf, int len) {
303 * Replace the buffer list on the socket with the data.
306 s->head = smalloc(sizeof(struct buffer));
308 struct buffer *walk = s->head->next;
310 struct buffer *tmp = walk;
315 s->head->next = NULL;
317 s->head->buflen = len;
318 memcpy(s->head->buf, buf, len);
321 * Set the Urgent marker.
323 s->sending_oob = len;
326 * Now try sending from the start of the buffer list.
332 int select_result(WPARAM wParam, LPARAM lParam) {
335 char buf[BUFFER_GRANULE];
339 /* wParam is the socket itself */
340 s = find234(sktree, (void *)wParam, cmpforsearch);
342 return 1; /* boggle */
344 if ((err = WSAGETSELECTERROR(lParam)) != 0) {
345 fatalbox(winsock_error_string(err));
348 switch (WSAGETSELECTEVENT(lParam)) {
350 ret = recv(s->s, buf, sizeof(buf), 0);
352 err = WSAGetLastError();
353 if (err == WSAEWOULDBLOCK) {
358 fatalbox(winsock_error_string(err));
360 int type = s->in_oob ? 2 : 0;
362 return s->receiver(s, type, buf, ret);
367 * Read all data up to the OOB marker, and send it to the
368 * receiver with urgent==1 (OOB pending).
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);
379 fatalbox(ret == 0 ? "Internal networking trouble" :
380 winsock_error_string(WSAGetLastError()));
382 return s->receiver(s, atmark ? 2 : 1, buf, ret);
390 /* Signal a close on the socket. */
391 return s->receiver(s, 0, NULL, 0);
399 * Each socket abstraction contains a `void *' private field in
400 * which the client can keep state.
402 void sk_set_private_ptr(Socket s, void *ptr) {
403 s->private_ptr = ptr;
405 void *sk_get_private_ptr(Socket s) {
406 return s->private_ptr;
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.
414 char *sk_addr_error(SockAddr addr) {
417 char *sk_socket_error(Socket s) {
422 * For Plink: enumerate all sockets currently active.
424 SOCKET first_socket(enum234 *e) {
425 Socket s = first234(sktree, e);
426 return s ? s->s : INVALID_SOCKET;
428 SOCKET next_socket(enum234 *e) {
429 Socket s = next234(e);
430 return s ? s->s : INVALID_SOCKET;