Implement `portfwd-loopback-choice'. Works on local side in Unix as
[u/mdw/putty] / unix / uxnet.c
1 /*
2 * Unix networking abstraction.
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <assert.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <sys/ioctl.h>
14 #include <arpa/inet.h>
15 #include <netinet/in.h>
16 #include <netinet/tcp.h>
17 #include <netdb.h>
18
19 #define DEFINE_PLUG_METHOD_MACROS
20 #include "putty.h"
21 #include "network.h"
22 #include "tree234.h"
23
24 #define ipv4_is_loopback(addr) (inet_netof(addr) == IN_LOOPBACKNET)
25
26 struct Socket_tag {
27 struct socket_function_table *fn;
28 /* the above variable absolutely *must* be the first in this structure */
29 char *error;
30 int s;
31 Plug plug;
32 void *private_ptr;
33 bufchain output_data;
34 int connected;
35 int writable;
36 int frozen; /* this causes readability notifications to be ignored */
37 int frozen_readable; /* this means we missed at least one readability
38 * notification while we were frozen */
39 int localhost_only; /* for listening sockets */
40 char oobdata[1];
41 int sending_oob;
42 int oobpending; /* is there OOB data available to read? */
43 int oobinline;
44 int pending_error; /* in case send() returns error */
45 int listener;
46 };
47
48 /*
49 * We used to typedef struct Socket_tag *Socket.
50 *
51 * Since we have made the networking abstraction slightly more
52 * abstract, Socket no longer means a tcp socket (it could mean
53 * an ssl socket). So now we must use Actual_Socket when we know
54 * we are talking about a tcp socket.
55 */
56 typedef struct Socket_tag *Actual_Socket;
57
58 struct SockAddr_tag {
59 char *error;
60 /* address family this belongs to, AF_INET for IPv4, AF_INET6 for IPv6. */
61 int family;
62 unsigned long address; /* Address IPv4 style. */
63 #ifdef IPV6
64 struct addrinfo *ai; /* Address IPv6 style. */
65 #endif
66 };
67
68 static tree234 *sktree;
69
70 static int cmpfortree(void *av, void *bv)
71 {
72 Actual_Socket a = (Actual_Socket) av, b = (Actual_Socket) bv;
73 int as = a->s, bs = b->s;
74 if (as < bs)
75 return -1;
76 if (as > bs)
77 return +1;
78 return 0;
79 }
80
81 static int cmpforsearch(void *av, void *bv)
82 {
83 Actual_Socket b = (Actual_Socket) bv;
84 int as = (int) av, bs = b->s;
85 if (as < bs)
86 return -1;
87 if (as > bs)
88 return +1;
89 return 0;
90 }
91
92 void sk_init(void)
93 {
94 sktree = newtree234(cmpfortree);
95 }
96
97 void sk_cleanup(void)
98 {
99 Actual_Socket s;
100 int i;
101
102 if (sktree) {
103 for (i = 0; (s = index234(sktree, i)) != NULL; i++) {
104 close(s->s);
105 }
106 }
107 }
108
109 char *error_string(int error)
110 {
111 return strerror(error);
112 }
113
114 SockAddr sk_namelookup(char *host, char **canonicalname)
115 {
116 SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
117 unsigned long a;
118 struct hostent *h = NULL;
119 char realhost[8192];
120
121 /* Clear the structure and default to IPv4. */
122 memset(ret, 0, sizeof(struct SockAddr_tag));
123 ret->family = 0; /* We set this one when we have resolved the host. */
124 *realhost = '\0';
125 ret->error = NULL;
126
127 if ((a = inet_addr(host)) == (unsigned long) INADDR_NONE) {
128 #ifdef IPV6
129 if (getaddrinfo(host, NULL, NULL, &ret->ai) == 0) {
130 ret->family = ret->ai->ai_family;
131 } else
132 #endif
133 {
134 /*
135 * Otherwise use the IPv4-only gethostbyname... (NOTE:
136 * we don't use gethostbyname as a fallback!)
137 */
138 if (ret->family == 0) {
139 /*debug(("Resolving \"%s\" with gethostbyname() (IPv4 only)...\n", host)); */
140 if ( (h = gethostbyname(host)) )
141 ret->family = AF_INET;
142 }
143 if (ret->family == 0) {
144 ret->error = (h_errno == HOST_NOT_FOUND ||
145 h_errno == NO_DATA ||
146 h_errno == NO_ADDRESS ? "Host does not exist" :
147 h_errno == TRY_AGAIN ?
148 "Temporary name service failure" :
149 "gethostbyname: unknown error");
150 return ret;
151 }
152 }
153
154 #ifdef IPV6
155 /* If we got an address info use that... */
156 if (ret->ai) {
157
158 /* Are we in IPv4 fallback mode? */
159 /* We put the IPv4 address into the a variable so we can further-on use the IPv4 code... */
160 if (ret->family == AF_INET)
161 memcpy(&a,
162 (char *) &((struct sockaddr_in *) ret->ai->
163 ai_addr)->sin_addr, sizeof(a));
164
165 /* Now let's find that canonicalname... */
166 if (getnameinfo((struct sockaddr *) ret->ai->ai_addr,
167 ret->family ==
168 AF_INET ? sizeof(struct sockaddr_in) :
169 sizeof(struct sockaddr_in6), realhost,
170 sizeof(realhost), NULL, 0, 0) != 0) {
171 strncpy(realhost, host, sizeof(realhost));
172 }
173 }
174 /* We used the IPv4-only gethostbyname()... */
175 else
176 #endif
177 {
178 memcpy(&a, h->h_addr, sizeof(a));
179 /* This way we are always sure the h->h_name is valid :) */
180 strncpy(realhost, h->h_name, sizeof(realhost));
181 }
182 } else {
183 /*
184 * This must be a numeric IPv4 address because it caused a
185 * success return from inet_addr.
186 */
187 ret->family = AF_INET;
188 strncpy(realhost, host, sizeof(realhost));
189 }
190 ret->address = ntohl(a);
191 realhost[lenof(realhost)-1] = '\0';
192 *canonicalname = smalloc(1+strlen(realhost));
193 strcpy(*canonicalname, realhost);
194 return ret;
195 }
196
197 void sk_getaddr(SockAddr addr, char *buf, int buflen)
198 {
199 #ifdef IPV6
200 if (addr->family == AF_INET) {
201 #endif
202 struct in_addr a;
203 a.s_addr = htonl(addr->address);
204 strncpy(buf, inet_ntoa(a), buflen);
205 #ifdef IPV6
206 } else {
207 FIXME; /* I don't know how to get a text form of an IPv6 address. */
208 }
209 #endif
210 }
211
212 int sk_addrtype(SockAddr addr)
213 {
214 return (addr->family == AF_INET ? ADDRTYPE_IPV4 : ADDRTYPE_IPV6);
215 }
216
217 void sk_addrcopy(SockAddr addr, char *buf)
218 {
219 #ifdef IPV6
220 if (addr->family == AF_INET) {
221 #endif
222 struct in_addr a;
223 a.s_addr = htonl(addr->address);
224 memcpy(buf, (char*) &a.s_addr, 4);
225 #ifdef IPV6
226 } else {
227 memcpy(buf, (char*) addr->ai, 16);
228 }
229 #endif
230 }
231
232 void sk_addr_free(SockAddr addr)
233 {
234 sfree(addr);
235 }
236
237 static Plug sk_tcp_plug(Socket sock, Plug p)
238 {
239 Actual_Socket s = (Actual_Socket) sock;
240 Plug ret = s->plug;
241 if (p)
242 s->plug = p;
243 return ret;
244 }
245
246 static void sk_tcp_flush(Socket s)
247 {
248 /*
249 * We send data to the socket as soon as we can anyway,
250 * so we don't need to do anything here. :-)
251 */
252 }
253
254 static void sk_tcp_close(Socket s);
255 static int sk_tcp_write(Socket s, char *data, int len);
256 static int sk_tcp_write_oob(Socket s, char *data, int len);
257 static void sk_tcp_set_private_ptr(Socket s, void *ptr);
258 static void *sk_tcp_get_private_ptr(Socket s);
259 static void sk_tcp_set_frozen(Socket s, int is_frozen);
260 static char *sk_tcp_socket_error(Socket s);
261
262 Socket sk_register(void *sock, Plug plug)
263 {
264 static struct socket_function_table fn_table = {
265 sk_tcp_plug,
266 sk_tcp_close,
267 sk_tcp_write,
268 sk_tcp_write_oob,
269 sk_tcp_flush,
270 sk_tcp_set_private_ptr,
271 sk_tcp_get_private_ptr,
272 sk_tcp_set_frozen,
273 sk_tcp_socket_error
274 };
275
276 Actual_Socket ret;
277
278 /*
279 * Create Socket structure.
280 */
281 ret = smalloc(sizeof(struct Socket_tag));
282 ret->fn = &fn_table;
283 ret->error = NULL;
284 ret->plug = plug;
285 bufchain_init(&ret->output_data);
286 ret->writable = 1; /* to start with */
287 ret->sending_oob = 0;
288 ret->frozen = 1;
289 ret->frozen_readable = 0;
290 ret->localhost_only = 0; /* unused, but best init anyway */
291 ret->pending_error = 0;
292 ret->oobpending = FALSE;
293 ret->listener = 0;
294
295 ret->s = (int)sock;
296
297 if (ret->s < 0) {
298 ret->error = error_string(errno);
299 return (Socket) ret;
300 }
301
302 ret->oobinline = 0;
303
304 add234(sktree, ret);
305
306 return (Socket) ret;
307 }
308
309 Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
310 int nodelay, Plug plug)
311 {
312 static struct socket_function_table fn_table = {
313 sk_tcp_plug,
314 sk_tcp_close,
315 sk_tcp_write,
316 sk_tcp_write_oob,
317 sk_tcp_flush,
318 sk_tcp_set_private_ptr,
319 sk_tcp_get_private_ptr,
320 sk_tcp_set_frozen,
321 sk_tcp_socket_error
322 };
323
324 int s;
325 #ifdef IPV6
326 struct sockaddr_in6 a6;
327 #endif
328 struct sockaddr_in a;
329 int err;
330 Actual_Socket ret;
331 short localport;
332
333 /*
334 * Create Socket structure.
335 */
336 ret = smalloc(sizeof(struct Socket_tag));
337 ret->fn = &fn_table;
338 ret->error = NULL;
339 ret->plug = plug;
340 bufchain_init(&ret->output_data);
341 ret->connected = 0; /* to start with */
342 ret->writable = 0; /* to start with */
343 ret->sending_oob = 0;
344 ret->frozen = 0;
345 ret->frozen_readable = 0;
346 ret->localhost_only = 0; /* unused, but best init anyway */
347 ret->pending_error = 0;
348 ret->oobpending = FALSE;
349 ret->listener = 0;
350
351 /*
352 * Open socket.
353 */
354 s = socket(addr->family, SOCK_STREAM, 0);
355 ret->s = s;
356
357 if (s < 0) {
358 ret->error = error_string(errno);
359 return (Socket) ret;
360 }
361
362 ret->oobinline = oobinline;
363 if (oobinline) {
364 int b = TRUE;
365 setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b));
366 }
367
368 if (nodelay) {
369 int b = TRUE;
370 setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b));
371 }
372
373 /*
374 * Bind to local address.
375 */
376 if (privport)
377 localport = 1023; /* count from 1023 downwards */
378 else
379 localport = 0; /* just use port 0 (ie kernel picks) */
380
381 /* Loop round trying to bind */
382 while (1) {
383 int retcode;
384
385 #ifdef IPV6
386 if (addr->family == AF_INET6) {
387 memset(&a6, 0, sizeof(a6));
388 a6.sin6_family = AF_INET6;
389 /*a6.sin6_addr = in6addr_any; *//* == 0 */
390 a6.sin6_port = htons(localport);
391 } else
392 #endif
393 {
394 a.sin_family = AF_INET;
395 a.sin_addr.s_addr = htonl(INADDR_ANY);
396 a.sin_port = htons(localport);
397 }
398 #ifdef IPV6
399 retcode = bind(s, (addr->family == AF_INET6 ?
400 (struct sockaddr *) &a6 :
401 (struct sockaddr *) &a),
402 (addr->family ==
403 AF_INET6 ? sizeof(a6) : sizeof(a)));
404 #else
405 retcode = bind(s, (struct sockaddr *) &a, sizeof(a));
406 #endif
407 if (retcode >= 0) {
408 err = 0;
409 break; /* done */
410 } else {
411 err = errno;
412 if (err != EADDRINUSE) /* failed, for a bad reason */
413 break;
414 }
415
416 if (localport == 0)
417 break; /* we're only looping once */
418 localport--;
419 if (localport == 0)
420 break; /* we might have got to the end */
421 }
422
423 if (err) {
424 ret->error = error_string(err);
425 return (Socket) ret;
426 }
427
428 /*
429 * Connect to remote address.
430 */
431 #ifdef IPV6
432 if (addr->family == AF_INET6) {
433 memset(&a, 0, sizeof(a));
434 a6.sin6_family = AF_INET6;
435 a6.sin6_port = htons((short) port);
436 a6.sin6_addr =
437 ((struct sockaddr_in6 *) addr->ai->ai_addr)->sin6_addr;
438 } else
439 #endif
440 {
441 a.sin_family = AF_INET;
442 a.sin_addr.s_addr = htonl(addr->address);
443 a.sin_port = htons((short) port);
444 }
445
446 if ((
447 #ifdef IPV6
448 connect(s, ((addr->family == AF_INET6) ?
449 (struct sockaddr *) &a6 : (struct sockaddr *) &a),
450 (addr->family == AF_INET6) ? sizeof(a6) : sizeof(a))
451 #else
452 connect(s, (struct sockaddr *) &a, sizeof(a))
453 #endif
454 ) < 0) {
455 /*
456 * FIXME: We are prepared to receive EWOULDBLOCK here,
457 * because we might want the connection to be made
458 * asynchronously; but how do we actually arrange this in
459 * Unix? I forget.
460 */
461 if ( errno != EWOULDBLOCK ) {
462 ret->error = error_string(errno);
463 return (Socket) ret;
464 }
465 } else {
466 /*
467 * If we _don't_ get EWOULDBLOCK, the connect has completed
468 * and we should set the socket as connected and writable.
469 */
470 ret->connected = 1;
471 ret->writable = 1;
472 }
473
474 add234(sktree, ret);
475
476 return (Socket) ret;
477 }
478
479 Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
480 {
481 static struct socket_function_table fn_table = {
482 sk_tcp_plug,
483 sk_tcp_close,
484 sk_tcp_write,
485 sk_tcp_write_oob,
486 sk_tcp_flush,
487 sk_tcp_set_private_ptr,
488 sk_tcp_get_private_ptr,
489 sk_tcp_set_frozen,
490 sk_tcp_socket_error
491 };
492
493 int s;
494 #ifdef IPV6
495 struct sockaddr_in6 a6;
496 #endif
497 struct sockaddr_in a;
498 int err;
499 Actual_Socket ret;
500 int retcode;
501 int on = 1;
502
503 /*
504 * Create Socket structure.
505 */
506 ret = smalloc(sizeof(struct Socket_tag));
507 ret->fn = &fn_table;
508 ret->error = NULL;
509 ret->plug = plug;
510 bufchain_init(&ret->output_data);
511 ret->writable = 0; /* to start with */
512 ret->sending_oob = 0;
513 ret->frozen = 0;
514 ret->frozen_readable = 0;
515 ret->localhost_only = local_host_only;
516 ret->pending_error = 0;
517 ret->oobpending = FALSE;
518 ret->listener = 1;
519
520 /*
521 * Open socket.
522 */
523 s = socket(AF_INET, SOCK_STREAM, 0);
524 ret->s = s;
525
526 if (s < 0) {
527 ret->error = error_string(errno);
528 return (Socket) ret;
529 }
530
531 ret->oobinline = 0;
532
533 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));
534
535 #ifdef IPV6
536 if (addr->family == AF_INET6) {
537 memset(&a6, 0, sizeof(a6));
538 a6.sin6_family = AF_INET6;
539 /* FIXME: srcaddr is ignored for IPv6, because I (SGT) don't
540 * know how to do it. :-) */
541 if (local_host_only)
542 a6.sin6_addr = in6addr_loopback;
543 else
544 a6.sin6_addr = in6addr_any;
545 a6.sin6_port = htons(port);
546 } else
547 #endif
548 {
549 int got_addr = 0;
550 a.sin_family = AF_INET;
551
552 /*
553 * Bind to source address. First try an explicitly
554 * specified one...
555 */
556 if (srcaddr) {
557 a.sin_addr.s_addr = inet_addr(srcaddr);
558 if (a.sin_addr.s_addr != INADDR_NONE) {
559 /* Override localhost_only with specified listen addr. */
560 ret->localhost_only = ipv4_is_loopback(a.sin_addr);
561 got_addr = 1;
562 }
563 }
564
565 /*
566 * ... and failing that, go with one of the standard ones.
567 */
568 if (!got_addr) {
569 if (local_host_only)
570 a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
571 else
572 a.sin_addr.s_addr = htonl(INADDR_ANY);
573 }
574
575 a.sin_port = htons((short)port);
576 }
577 #ifdef IPV6
578 retcode = bind(s, (addr->family == AF_INET6 ?
579 (struct sockaddr *) &a6 :
580 (struct sockaddr *) &a),
581 (addr->family ==
582 AF_INET6 ? sizeof(a6) : sizeof(a)));
583 #else
584 retcode = bind(s, (struct sockaddr *) &a, sizeof(a));
585 #endif
586 if (retcode >= 0) {
587 err = 0;
588 } else {
589 err = errno;
590 }
591
592 if (err) {
593 ret->error = error_string(err);
594 return (Socket) ret;
595 }
596
597
598 if (listen(s, SOMAXCONN) < 0) {
599 close(s);
600 ret->error = error_string(errno);
601 return (Socket) ret;
602 }
603
604 add234(sktree, ret);
605
606 return (Socket) ret;
607 }
608
609 static void sk_tcp_close(Socket sock)
610 {
611 Actual_Socket s = (Actual_Socket) sock;
612
613 del234(sktree, s);
614 close(s->s);
615 sfree(s);
616 }
617
618 /*
619 * The function which tries to send on a socket once it's deemed
620 * writable.
621 */
622 void try_send(Actual_Socket s)
623 {
624 while (s->sending_oob || bufchain_size(&s->output_data) > 0) {
625 int nsent;
626 int err;
627 void *data;
628 int len, urgentflag;
629
630 if (s->sending_oob) {
631 urgentflag = MSG_OOB;
632 len = s->sending_oob;
633 data = &s->oobdata;
634 } else {
635 urgentflag = 0;
636 bufchain_prefix(&s->output_data, &data, &len);
637 }
638 nsent = send(s->s, data, len, urgentflag);
639 noise_ultralight(nsent);
640 if (nsent <= 0) {
641 err = (nsent < 0 ? errno : 0);
642 if (err == EWOULDBLOCK) {
643 /*
644 * Perfectly normal: we've sent all we can for the moment.
645 */
646 s->writable = FALSE;
647 return;
648 } else if (nsent == 0 ||
649 err == ECONNABORTED || err == ECONNRESET) {
650 /*
651 * If send() returns CONNABORTED or CONNRESET, we
652 * unfortunately can't just call plug_closing(),
653 * because it's quite likely that we're currently
654 * _in_ a call from the code we'd be calling back
655 * to, so we'd have to make half the SSH code
656 * reentrant. Instead we flag a pending error on
657 * the socket, to be dealt with (by calling
658 * plug_closing()) at some suitable future moment.
659 */
660 s->pending_error = err;
661 return;
662 } else {
663 /* We're inside the Unix frontend here, so we know
664 * that the frontend handle is unnecessary. */
665 logevent(NULL, error_string(err));
666 fatalbox("%s", error_string(err));
667 }
668 } else {
669 if (s->sending_oob) {
670 if (nsent < len) {
671 memmove(s->oobdata, s->oobdata+nsent, len-nsent);
672 s->sending_oob = len - nsent;
673 } else {
674 s->sending_oob = 0;
675 }
676 } else {
677 bufchain_consume(&s->output_data, nsent);
678 }
679 }
680 }
681 }
682
683 static int sk_tcp_write(Socket sock, char *buf, int len)
684 {
685 Actual_Socket s = (Actual_Socket) sock;
686
687 /*
688 * Add the data to the buffer list on the socket.
689 */
690 bufchain_add(&s->output_data, buf, len);
691
692 /*
693 * Now try sending from the start of the buffer list.
694 */
695 if (s->writable)
696 try_send(s);
697
698 return bufchain_size(&s->output_data);
699 }
700
701 static int sk_tcp_write_oob(Socket sock, char *buf, int len)
702 {
703 Actual_Socket s = (Actual_Socket) sock;
704
705 /*
706 * Replace the buffer list on the socket with the data.
707 */
708 bufchain_clear(&s->output_data);
709 assert(len <= sizeof(s->oobdata));
710 memcpy(s->oobdata, buf, len);
711 s->sending_oob = len;
712
713 /*
714 * Now try sending from the start of the buffer list.
715 */
716 if (s->writable)
717 try_send(s);
718
719 return s->sending_oob;
720 }
721
722 int select_result(int fd, int event)
723 {
724 int ret;
725 int err;
726 char buf[20480]; /* nice big buffer for plenty of speed */
727 Actual_Socket s;
728 u_long atmark;
729
730 /* Find the Socket structure */
731 s = find234(sktree, (void *) fd, cmpforsearch);
732 if (!s)
733 return 1; /* boggle */
734
735 noise_ultralight(event);
736
737 switch (event) {
738 #ifdef FIXME_NONBLOCKING_CONNECTIONS
739 case FIXME: /* connected */
740 s->connected = s->writable = 1;
741 break;
742 #endif
743 case 4: /* exceptional */
744 if (!s->oobinline) {
745 /*
746 * On a non-oobinline socket, this indicates that we
747 * can immediately perform an OOB read and get back OOB
748 * data, which we will send to the back end with
749 * type==2 (urgent data).
750 */
751 ret = recv(s->s, buf, sizeof(buf), MSG_OOB);
752 noise_ultralight(ret);
753 if (ret <= 0) {
754 char *str = (ret == 0 ? "Internal networking trouble" :
755 error_string(errno));
756 /* We're inside the Unix frontend here, so we know
757 * that the frontend handle is unnecessary. */
758 logevent(NULL, str);
759 fatalbox("%s", str);
760 } else {
761 return plug_receive(s->plug, 2, buf, ret);
762 }
763 break;
764 }
765
766 /*
767 * If we reach here, this is an oobinline socket, which
768 * means we should set s->oobpending and then deal with it
769 * when we get called for the readability event (which
770 * should also occur).
771 */
772 s->oobpending = TRUE;
773 break;
774 case 1: /* readable; also acceptance */
775 if (s->listener) {
776 /*
777 * On a listening socket, the readability event means a
778 * connection is ready to be accepted.
779 */
780 struct sockaddr_in isa;
781 int addrlen = sizeof(struct sockaddr_in);
782 int t; /* socket of connection */
783
784 memset(&isa, 0, sizeof(struct sockaddr_in));
785 err = 0;
786 t = accept(s->s,(struct sockaddr *)&isa,&addrlen);
787 if (t < 0) {
788 break;
789 }
790
791 if (s->localhost_only && !ipv4_is_loopback(isa.sin_addr)) {
792 close(t); /* someone let nonlocal through?! */
793 } else if (plug_accepting(s->plug, (void*)t)) {
794 close(t); /* denied or error */
795 }
796 break;
797 }
798
799 /*
800 * If we reach here, this is not a listening socket, so
801 * readability really means readability.
802 */
803
804 /* In the case the socket is still frozen, we don't even bother */
805 if (s->frozen) {
806 s->frozen_readable = 1;
807 break;
808 }
809
810 /*
811 * We have received data on the socket. For an oobinline
812 * socket, this might be data _before_ an urgent pointer,
813 * in which case we send it to the back end with type==1
814 * (data prior to urgent).
815 */
816 if (s->oobinline && s->oobpending) {
817 atmark = 1;
818 if (ioctl(s->s, SIOCATMARK, &atmark) == 0 && atmark)
819 s->oobpending = FALSE; /* clear this indicator */
820 } else
821 atmark = 1;
822
823 ret = recv(s->s, buf, s->oobpending ? 1 : sizeof(buf), 0);
824 noise_ultralight(ret);
825 if (ret < 0) {
826 if (errno == EWOULDBLOCK) {
827 break;
828 }
829 }
830 if (ret < 0) {
831 return plug_closing(s->plug, error_string(errno), errno, 0);
832 } else if (0 == ret) {
833 return plug_closing(s->plug, NULL, 0, 0);
834 } else {
835 return plug_receive(s->plug, atmark ? 0 : 1, buf, ret);
836 }
837 break;
838 case 2: /* writable */
839 {
840 int bufsize_before, bufsize_after;
841 s->writable = 1;
842 bufsize_before = s->sending_oob + bufchain_size(&s->output_data);
843 try_send(s);
844 bufsize_after = s->sending_oob + bufchain_size(&s->output_data);
845 if (bufsize_after < bufsize_before)
846 plug_sent(s->plug, bufsize_after);
847 }
848 break;
849 }
850
851 return 1;
852 }
853
854 /*
855 * Deal with socket errors detected in try_send().
856 */
857 void net_pending_errors(void)
858 {
859 int i;
860 Actual_Socket s;
861
862 /*
863 * This might be a fiddly business, because it's just possible
864 * that handling a pending error on one socket might cause
865 * others to be closed. (I can't think of any reason this might
866 * happen in current SSH implementation, but to maintain
867 * generality of this network layer I'll assume the worst.)
868 *
869 * So what we'll do is search the socket list for _one_ socket
870 * with a pending error, and then handle it, and then search
871 * the list again _from the beginning_. Repeat until we make a
872 * pass with no socket errors present. That way we are
873 * protected against the socket list changing under our feet.
874 */
875
876 do {
877 for (i = 0; (s = index234(sktree, i)) != NULL; i++) {
878 if (s->pending_error) {
879 /*
880 * An error has occurred on this socket. Pass it to the
881 * plug.
882 */
883 plug_closing(s->plug, error_string(s->pending_error),
884 s->pending_error, 0);
885 break;
886 }
887 }
888 } while (s);
889 }
890
891 /*
892 * Each socket abstraction contains a `void *' private field in
893 * which the client can keep state.
894 */
895 static void sk_tcp_set_private_ptr(Socket sock, void *ptr)
896 {
897 Actual_Socket s = (Actual_Socket) sock;
898 s->private_ptr = ptr;
899 }
900
901 static void *sk_tcp_get_private_ptr(Socket sock)
902 {
903 Actual_Socket s = (Actual_Socket) sock;
904 return s->private_ptr;
905 }
906
907 /*
908 * Special error values are returned from sk_namelookup and sk_new
909 * if there's a problem. These functions extract an error message,
910 * or return NULL if there's no problem.
911 */
912 char *sk_addr_error(SockAddr addr)
913 {
914 return addr->error;
915 }
916 static char *sk_tcp_socket_error(Socket sock)
917 {
918 Actual_Socket s = (Actual_Socket) sock;
919 return s->error;
920 }
921
922 static void sk_tcp_set_frozen(Socket sock, int is_frozen)
923 {
924 Actual_Socket s = (Actual_Socket) sock;
925 if (s->frozen == is_frozen)
926 return;
927 s->frozen = is_frozen;
928 if (!is_frozen && s->frozen_readable) {
929 char c;
930 recv(s->s, &c, 1, MSG_PEEK);
931 }
932 s->frozen_readable = 0;
933 }
934
935 /*
936 * For Unix select()-based frontends: enumerate all sockets
937 * currently active, and state whether we currently wish to receive
938 * select events on them for reading, writing and exceptional
939 * status.
940 */
941 static void set_rwx(Actual_Socket s, int *rwx)
942 {
943 int val = 0;
944 if (s->connected && !s->frozen)
945 val |= 1 | 4; /* read, except */
946 if (bufchain_size(&s->output_data))
947 val |= 2; /* write */
948 if (s->listener)
949 val |= 1; /* read == accept */
950 *rwx = val;
951 }
952
953 int first_socket(int *state, int *rwx)
954 {
955 Actual_Socket s;
956 *state = 0;
957 s = index234(sktree, (*state)++);
958 if (s)
959 set_rwx(s, rwx);
960 return s ? s->s : -1;
961 }
962
963 int next_socket(int *state, int *rwx)
964 {
965 Actual_Socket s = index234(sktree, (*state)++);
966 if (s)
967 set_rwx(s, rwx);
968 return s ? s->s : -1;
969 }
970
971 int net_service_lookup(char *service)
972 {
973 struct servent *se;
974 se = getservbyname(service, NULL);
975 if (se != NULL)
976 return ntohs(se->s_port);
977 else
978 return 0;
979 }