]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - unix/uxnet.c
Implement `portfwd-loopback-choice'. Works on local side in Unix as
[PuTTY.git] / 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 }