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 SockAddr sk_namelookup(char *host, char **canonicalname) {
60 SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
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");
73 memcpy (&a, h->h_addr, sizeof(a));
74 *canonicalname = h->h_name;
77 *canonicalname = host;
79 ret->address = ntohl(a);
84 void sk_addr_free(SockAddr addr) {
88 Socket sk_new(SockAddr addr, int port, sk_receiver_t receiver) {
94 extern char *do_select(SOCKET skt, int startup);
97 * Create Socket structure.
99 ret = smalloc(sizeof(struct Socket_tag));
101 ret->receiver = receiver;
102 ret->head = ret->tail = NULL;
103 ret->writable = 1; /* to start with */
105 ret->sending_oob = 0;
110 s = socket(AF_INET, SOCK_STREAM, 0);
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");
122 * Bind to local address.
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");
135 * Connect to remote address.
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");
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);
162 void sk_close(Socket s) {
169 char *winsock_error_string(int 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";
211 * The function which tries to send on a socket once it's deemed
214 void try_send(Socket s) {
220 if (s->sending_oob) {
221 urgentflag = MSG_OOB;
222 len = s->sending_oob;
225 len = s->head->buflen - s->head->bufpos;
228 nsent = send(s->s, s->head->buf + s->head->bufpos, len, urgentflag);
229 noise_ultralight(nsent);
231 err = (nsent < 0 ? WSAGetLastError() : 0);
232 if (err == WSAEWOULDBLOCK) {
233 /* Perfectly normal: we've sent all we can for the moment. */
236 } else if (nsent == 0 ||
237 err == WSAECONNABORTED ||
238 err == WSAECONNRESET) {
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.
250 fatalbox(winsock_error_string(err));
252 fatalbox(winsock_error_string(err));
255 s->head->bufpos += nsent;
257 s->sending_oob -= nsent;
258 if (s->head->bufpos >= s->head->buflen) {
259 struct buffer *tmp = s->head;
269 void sk_write(Socket s, char *buf, int len) {
271 * Add the data to the buffer list on the socket.
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);
278 s->tail->buflen += copylen;
281 int grainlen = min(len, BUFFER_GRANULE);
282 struct buffer *newbuf;
283 newbuf = smalloc(sizeof(struct buffer));
285 newbuf->buflen = grainlen;
286 memcpy(newbuf->buf, buf, grainlen);
290 s->tail->next = newbuf;
292 s->head = s->tail = newbuf;
298 * Now try sending from the start of the buffer list.
304 void sk_write_oob(Socket s, char *buf, int len) {
306 * Replace the buffer list on the socket with the data.
309 s->head = smalloc(sizeof(struct buffer));
311 struct buffer *walk = s->head->next;
313 struct buffer *tmp = walk;
318 s->head->next = NULL;
320 s->head->buflen = len;
321 memcpy(s->head->buf, buf, len);
324 * Set the Urgent marker.
326 s->sending_oob = len;
329 * Now try sending from the start of the buffer list.
335 int select_result(WPARAM wParam, LPARAM lParam) {
338 char buf[BUFFER_GRANULE];
342 /* wParam is the socket itself */
343 s = find234(sktree, (void *)wParam, cmpforsearch);
345 return 1; /* boggle */
347 if ((err = WSAGETSELECTERROR(lParam)) != 0) {
348 fatalbox(winsock_error_string(err));
351 noise_ultralight(lParam);
353 switch (WSAGETSELECTEVENT(lParam)) {
355 ret = recv(s->s, buf, sizeof(buf), 0);
357 err = WSAGetLastError();
358 if (err == WSAEWOULDBLOCK) {
363 fatalbox(winsock_error_string(err));
365 int type = s->in_oob ? 2 : 0;
367 return s->receiver(s, type, buf, ret);
372 * Read all data up to the OOB marker, and send it to the
373 * receiver with urgent==1 (OOB pending).
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);
385 fatalbox(ret == 0 ? "Internal networking trouble" :
386 winsock_error_string(WSAGetLastError()));
388 return s->receiver(s, atmark ? 2 : 1, buf, ret);
396 /* Signal a close on the socket. */
397 return s->receiver(s, 0, NULL, 0);
405 * Each socket abstraction contains a `void *' private field in
406 * which the client can keep state.
408 void sk_set_private_ptr(Socket s, void *ptr) {
409 s->private_ptr = ptr;
411 void *sk_get_private_ptr(Socket s) {
412 return s->private_ptr;
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.
420 char *sk_addr_error(SockAddr addr) {
423 char *sk_socket_error(Socket s) {
428 * For Plink: enumerate all sockets currently active.
430 SOCKET first_socket(enum234 *e) {
431 Socket s = first234(sktree, e);
432 return s ? s->s : INVALID_SOCKET;
434 SOCKET next_socket(enum234 *e) {
435 Socket s = next234(e);
436 return s ? s->s : INVALID_SOCKET;