1 /*
2  * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
3  *               2009, 2010, 2011, 2012, 2013, 2014, 2016
4  *      Inferno Nettverk A/S, Norway.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. The above copyright notice, this list of conditions and the following
10  *    disclaimer must appear in all copies of the software, derivative works
11  *    or modified versions, and any portions thereof, aswell as in all
12  *    supporting documentation.
13  * 2. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by
16  *      Inferno Nettverk A/S, Norway.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * Inferno Nettverk A/S requests users of this software to return to
32  *
33  *  Software Distribution Coordinator  or  sdc@inet.no
34  *  Inferno Nettverk A/S
35  *  Oslo Research Park
36  *  Gaustadall�en 21
37  *  NO-0349 Oslo
38  *  Norway
39  *
40  * any improvements or extensions that they make and grant Inferno Nettverk A/S
41  * the rights to redistribute these changes.
42  *
43  */
44 
45 #include "common.h"
46 
47 static const char rcsid[] =
48 "$Id: io.c,v 1.342.4.7.2.3 2017/01/31 08:17:38 karls Exp $";
49 
50 static void
51 print_selectfds(const char *preamble, const int docheck, const int nfds,
52                 fd_set *rset, fd_set *bufrset, fd_set *buffwset,
53                 fd_set *wset, fd_set *xset,
54                 const struct timespec *timeout);
55 
56 ssize_t
socks_recvfromn(s,buf,len,minread,flags,from,fromlen,recvflags,auth)57 socks_recvfromn(s, buf, len, minread, flags, from, fromlen, recvflags, auth)
58    const int s;
59    void *buf;
60    const size_t len;
61    const size_t minread;
62    const int flags;
63    struct sockaddr_storage *from;
64    socklen_t *fromlen;
65    recvfrom_info_t *recvflags;
66    authmethod_t *auth;
67 {
68    const char *function = "socks_recvfromn()";
69    static fd_set *rset;
70    ssize_t p;
71    size_t left;
72 
73    if (rset == NULL)
74       rset = allocate_maxsize_fdset();
75 
76    left = len;
77    do {
78 #if SOCKS_CLIENT
79       /*
80        * If this changes between now and the return of socks_recvfrom(),
81        * the change must have been done in the signal handler.  We then
82        * assume it's due to us receiving a signal from our connectchild
83        * process.
84        */
85       sockscf.state.handledsignal = 0;
86 #endif /* SOCKS_CLIENT */
87 
88       if ((p = socks_recvfrom(s,
89                               &((char *)buf)[len - left],
90                               left,
91                               flags,
92                               from,
93                               fromlen,
94                               recvflags,
95                               auth)) == -1) {
96 #if !SOCKS_CLIENT
97 
98          if (errno == EINTR) {
99             errno = 0;
100             continue; /* just retry directly. */
101          }
102 
103          if (ERRNOISTMP(errno) && len - left < minread) {
104             /*
105              * Some other error, also non-fatal though, so also retry.
106              */
107 
108             errno = 0;
109             FD_ZERO(rset);
110             FD_SET(s, rset);
111 
112             if (select(s + 1, rset, NULL, NULL, NULL) == 1)
113                continue;
114 
115             if (errno == EINTR)
116                continue;
117 
118             SWARNX(errno); /* unexpected error. */
119             break;
120          }
121          else {
122             slog(LOG_DEBUG, "%s: non-temporary read error: %s",
123                  function, strerror(errno));
124 
125             break;
126          }
127 
128 #else /* SOCKS_CLIENT */
129 
130          if (errno == EINTR) {
131             if (sockscf.state.handledsignal) {
132               /*
133                * Can't know for sure, but assume we were interrupted due
134                * to a signal from our own non-blocking connect child,
135                * presumably signalling a connect(2) unrelated to this socket
136                * has completed.
137                */
138                slog(LOG_DEBUG,
139                     "%s: read was interrupted, but looks like it could be due "
140                     "to our own signal (signal #%d/%s), so assume we should "
141                     "retry",
142                     function,
143                     (int)sockscf.state.handledsignal,
144                     signal2string(sockscf.state.handledsignal));
145 
146                sockscf.state.handledsignal = 0;
147                continue;
148             }
149          }
150 
151          /*
152           * Else: not a signal related to us.  Break out and let client retry
153           * itself if it wants to.
154           */
155          break;
156 #endif /* SOCKS_CLIENT */
157       }
158       else if (p == 0)
159          break;
160 
161       SASSERTX(p > 0);
162 
163       left -= (size_t)p;
164    } while (len - left < minread);
165 
166    if (left == len)
167       return p;   /* nothing read. */
168 
169    return len - left;
170 }
171 
172 ssize_t
socks_sendton(s,buf,len,minwrite,flags,to,tolen,sendtoflags,auth)173 socks_sendton(s, buf, len, minwrite, flags, to, tolen, sendtoflags, auth)
174    int s;
175    const void *buf;
176    size_t len;
177    const size_t minwrite;
178    int flags;
179    const struct sockaddr_storage *to;
180    socklen_t tolen;
181    sendto_info_t *sendtoflags;
182    authmethod_t *auth;
183 {
184    const char *function = "socks_sendton()";
185    static fd_set *wset;
186    ssize_t p;
187    size_t left = len;
188 
189    if (wset == NULL)
190       wset = allocate_maxsize_fdset();
191 
192    SASSERTX(minwrite <= len);
193 
194    do {
195       if ((p = socks_sendto(s,
196                             &((const char *)buf)[len - left],
197                             left,
198                             flags,
199                             to,
200                             tolen,
201                             sendtoflags,
202                             auth)) == -1) {
203 #if !SOCKS_CLIENT
204          if (errno == EINTR)
205             continue;
206 #endif /* !SOCKS_CLIENT */
207 
208          if ((errno == EAGAIN || errno == EWOULDBLOCK) && minwrite > 0) {
209             errno = 0;
210 
211             FD_ZERO(wset);
212             FD_SET(s, wset);
213             if (selectn(s + 1, NULL, NULL, NULL, wset, NULL, NULL) == -1) {
214                if (errno != EINTR)
215                   swarn("%s: select()", function);
216 
217                return -1;
218             }
219 
220             continue;
221          }
222 
223          break;
224       }
225 
226       left -= (size_t)p;
227 
228       if (sendtoflags != NULL)
229          sendtoflags->tosocket += p;
230    } while ((len - left) < minwrite);
231 
232    return len - left;
233 }
234 
235 ssize_t
socks_recvfrom(s,buf,len,flags,from,fromlen,recvflags,auth)236 socks_recvfrom(s, buf, len, flags, from, fromlen, recvflags, auth)
237    int s;
238    void *buf;
239    size_t len;
240    int flags;
241    struct sockaddr_storage *from;
242    socklen_t *fromlen;
243    recvfrom_info_t *recvflags;
244    authmethod_t *auth;
245 {
246    const char *function = "socks_recvfrom()";
247    ssize_t r;
248 #if !SOCKS_CLIENT
249    size_t toread, tocaller, tobuf;
250    ssize_t readfrombuf;
251    char tmpbuf[MAX(sizeof(sockd_io_t), SOCKD_BUFSIZE)];
252 #endif /* !SOCKS_CLIENT */
253 
254    if (sockscf.option.debug >= DEBUG_VERBOSE)
255       slog(LOG_DEBUG, "%s: fd %d, len %lu, flags %d",
256            function, s, (unsigned long)len, flags);
257 
258    if (auth != NULL)
259       SASSERTX(authmethodisknown(auth->method));
260 
261    if (recvflags != NULL) {
262       recvflags->flags      = 0;
263       recvflags->fromsocket = 0;
264       timerclear(&recvflags->ts);
265    }
266 
267 #if HAVE_GSSAPI
268    if (auth != NULL
269    && auth->method == AUTHMETHOD_GSSAPI && auth->mdata.gssapi.state.wrap)
270       return gssapi_decode_read(s,
271                                 buf,
272                                 len,
273                                 flags,
274                                 from,
275                                 fromlen,
276                                 recvflags,
277                                 &auth->mdata.gssapi.state);
278 #endif /* HAVE_GSSAPI */
279 
280 #if SOCKS_CLIENT
281    SASSERTX(recvflags == NULL);
282 
283    /*
284     * no buffering is provided by us for the client, except if using gssapi,
285     * and that is handled in the above function.
286     */
287    if (from == NULL && flags == 0)
288       /* may not be a socket and read(2) will work just as well then. */
289       r = read(s, buf, len);
290    else
291       r = recvfrom(s, buf, len, flags, TOSA(from), fromlen);
292 
293    if (sockscf.option.debug >= DEBUG_VERBOSE)
294       slog(LOG_DEBUG, "%s: read %ld byte%s, errno = %d (%s)",
295            function, (long)r, r == 1 ? "" : "s", errno, strerror(errno));
296 
297    if (r >= 0)
298       /*
299        * Some systems return bytes read, yet still set errno.  In particular,
300        * OpenBSD 4.5's thread implementation does this sometimes.
301        * Clearly wrong, but what can we do. :-/
302        */
303       errno = 0;
304 
305    return r;
306 
307 #else /* SOCKS_SERVER */
308 
309    /*
310     * Return data from the buffer first, if non-empty, then read data from
311     * socket if needed.
312     */
313 
314    /*
315     * mother does not use iobuf's, so don't waste time scanning through
316     * a static array of iobuf's looking for something that is not there.
317     */
318    if (sockscf.state.type == PROC_MOTHER) {
319       SASSERTX(flags      == 0);
320       SASSERTX(from       == NULL);
321       SASSERTX(fromlen    == NULL);
322       SASSERTX(auth       == NULL);
323       SASSERTX(recvflags  == NULL);
324 
325       return read(s, buf, len);
326    }
327 
328    /*
329     * else; child.  Sockd children use iobufs, but mother does not.
330     */
331 
332    if ((readfrombuf = socks_getfrombuffer(s, flags, READ_BUF, 0, buf, len)) > 0)
333    {
334       if (sockscf.option.debug >= DEBUG_VERBOSE) {
335          slog(LOG_DEBUG, "%s: read %lu byte from buf, %lu bytes left in buf",
336               function,
337               (unsigned long)readfrombuf,
338               (unsigned long)socks_bytesinbuffer(s, READ_BUF, 0));
339       }
340    }
341 
342    if ((size_t)readfrombuf >= len)
343       return readfrombuf;
344 
345    /*
346     * If we have a buffer allocated, assume it's safe to read
347     * as much as it can hold, as it make things much more efficient
348     * to do subsequent reads from the buffer (i.e., like fread()).
349     */
350    if (socks_getbuffer(s) == NULL)
351       r = len;
352    else
353       r = MIN(socks_freeinbuffer(s, READ_BUF), sizeof(tmpbuf));
354 
355    if (r <= 0)
356       return readfrombuf;
357 
358    /*
359     * Now read as much as we can into the tmpbuf, and later check what
360     * can be copied back to caller this time, and what needs to be stored
361     * in iobuf for later.
362     */
363 
364    toread = (size_t)r;
365 
366    if (from == NULL && flags == 0 && recvflags == NULL)
367       /*
368        * may not be a socket and read(2) will work just as well then,
369        * while recvfrom(2) will fail if not a socket.
370        */
371       r = read(s, tmpbuf, toread);
372    else {
373       const socklen_t passed_fromlen = (fromlen == NULL ? 0 : *fromlen);
374       static int failures, failed_socket;
375       struct msghdr msg;
376       struct iovec iov = { tmpbuf, toread };
377       CMSG_AALLOC(cmsg, sizeof(recvflags->ts));
378 
379       bzero(&msg, sizeof(msg));
380       msg.msg_name    = from;
381       msg.msg_namelen = passed_fromlen;
382       msg.msg_iov     = &iov;
383       msg.msg_iovlen  = 1;
384 
385       CMSG_SETHDR_RECV(msg, cmsg, CMSG_MEMSIZE(cmsg));
386 
387       if ((r = recvmsgn(s, &msg, flags)) == -1) {
388          slog(LOG_DEBUG, "%s: recvmsgn() on fd %d failed (%s)",
389               function, s, strerror(errno));
390 
391 #if HAVE_LINUX_BUGS
392          if (errno == 0) {
393             const int errno_s = errno;
394             int isudpsocket;
395 
396             if (recvflags != NULL)
397                isudpsocket = recvflags->type == SOCK_DGRAM;
398             else {
399                iobuffer_t *iobuf;
400 
401                if ((iobuf = socks_getbuffer(s)) != NULL)
402                   isudpsocket = (iobuf->stype == SOCK_DGRAM);
403                else {
404                   int type;
405                   socklen_t typelen = sizeof(type);
406 
407                   if (getsockopt(s, SOL_SOCKET, SO_TYPE, &type, &typelen) == 0
408                   &&  type == SOCK_DGRAM)
409                      isudpsocket = 1;
410                   else
411                      isudpsocket = 0;
412                }
413             }
414 
415             if (isudpsocket) {
416                swarnx("%s: trying to work around Linux bug.  recvmsg(2) "
417                       "returned -1, but did not set errno so we can't know "
418                       "the reason for the failure.  Setting to EAGAIN and "
419                       "hoping the best",
420                       function);
421 
422                errno = EAGAIN;
423             }
424             else
425                errno = errno_s;
426          }
427 #endif
428       }
429       else {
430          if (socks_msghaserrors(function, &msg))
431             r = -1;
432          else if (msg.msg_namelen < sizeof(struct sockaddr_in)
433          &&       passed_fromlen >= sizeof(struct sockaddr_in)) {
434             /*
435              * Solaris, at least 2.5.1, sometimes fails to return the
436              * srcaddress in recvfrom(2).
437              * More recently it has also been seen at least once on
438              * OS X, Kernel Version 10.8.0, at a point where recvmsg(2)
439              * returned 0.
440              */
441 
442             swarnx("%s: kernel/system error: did not get a valid src "
443                    "address from recvfrom(2) on fd %d.  Got a fromlen "
444                    "of %ld for a %ld byte packet",
445                    function, s, (long)*fromlen, (long)r);
446 
447             if (failures++ >= 4) {
448                /*
449                 * don't know if it's the same socket that has failed each
450                 * time, but this is a kernel error and should never happen
451                 * anyway, so go along like this for now.
452                 */
453                swarnx("%s: giving up after %d recvfrom(2) failures",
454                       function, failures);
455 
456                /* reset. */
457                failures      = 0;
458                errno         = 0;
459 
460                return -1;
461             }
462             else {
463                failed_socket = s;
464 
465                errno         = EAGAIN;
466                return -1;
467             }
468          }
469          else {
470             if (failed_socket == s)
471                failures = 0; /* reset on first success. */
472 
473             if (recvflags != NULL) {
474                recvflags->flags = msg.msg_flags;
475 
476 #if HAVE_SO_TIMESTAMP
477                if (CMSG_TOTLEN(msg) != 0) {
478                   if (!CMSG_RCPTLEN_ISOK(msg, sizeof(struct timeval))) {
479                      swarnx("%s: did not receive a timestamp for packet "
480                             "of length %lu (cmsglen is %lu)",
481                             function,
482                             (unsigned long)r,
483                             (unsigned long)CMSG_TOTLEN(msg));
484 
485                      timerclear(&recvflags->ts);
486                   }
487                   else {
488                      SASSERTX(cmsg->cmsg_level == SOL_SOCKET);
489                      SASSERTX(cmsg->cmsg_type  == SCM_TIMESTAMP);
490 
491                      CMSG_GETOBJECT(recvflags->ts, cmsg, 0);
492                   }
493                }
494                else
495                   timerclear(&recvflags->ts);
496 
497 #else /* !HAVE_SO_TIMESTAMP */
498                timerclear(&recvflags->ts);
499 
500 #endif /* !HAVE_SO_TIMESTAMP */
501             }
502          }
503       }
504    }
505 
506    if (r == -1 && recvflags != NULL && recvflags->type == SOCK_DGRAM)
507       if (ERRNOISPREVIOUSPACKET(errno))
508          log_writefailed(recvflags->side == INTERNALIF ?
509                                                         EXTERNALIF : INTERNALIF,
510                          s,
511                          &recvflags->peer);
512 
513    if (sockscf.option.debug >= DEBUG_VERBOSE)
514       slog(LOG_DEBUG,
515            "%s: read %ld/%lu bytes from socket, fd %d, errno = %d (%s)",
516            function,
517            (long)r,
518            (unsigned long)toread,
519            s,
520            errno,
521            strerror(errno));
522 
523    if (r <= 0) {
524       if (readfrombuf <= 0)
525          return r;
526       /*
527        * Else: even if read from socket failed, read from buf did not.
528        */
529       errno = 0;
530       return readfrombuf;
531    }
532    else {
533       if (recvflags != NULL)
534          recvflags->fromsocket += r;
535    }
536 
537    tocaller = MIN((size_t)r, len - readfrombuf);
538 
539    if (flags & MSG_PEEK)
540       /*
541        * nothing to add to buffer now; will still be in socket next time
542        * and we will add it then.
543        */
544       tobuf = 0;
545    else
546       /*
547        * Add to buffer what we are not returning to caller now.
548        */
549       tobuf = (size_t)r - tocaller;
550 
551    memcpy((char *)buf + readfrombuf, tmpbuf, tocaller);
552 
553    if (tobuf > 0)
554       socks_addtobuffer(s, READ_BUF, 0, tmpbuf + tocaller, tobuf);
555 
556    return readfrombuf + tocaller;
557 #endif /* SOCKS_SERVER */
558 }
559 
560 ssize_t
socks_sendto(s,msg,len,flags,to,tolen,sendtoflags,auth)561 socks_sendto(s, msg, len, flags, to, tolen, sendtoflags, auth)
562    int s;
563    const void *msg;
564    size_t len;
565    int flags;
566    const struct sockaddr_storage *to;
567    socklen_t tolen;
568    sendto_info_t *sendtoflags;
569    authmethod_t *auth;
570 {
571    const char *function = "socks_sendto()";
572    ssize_t written;
573 #if !SOCKS_CLIENT
574    ssize_t towrite, written_fb, p;
575    char buf[MAX(sizeof(sockd_io_t), SOCKD_BUFSIZE)];
576 #endif /* !SOCKS_CLIENT */
577 
578    if (sockscf.option.debug >= DEBUG_VERBOSE)
579       slog(LOG_DEBUG, "%s: fd %d, len %lu, flags %d, to = %s",
580            function,
581            s,
582            (long unsigned)len,
583            flags,
584            to == NULL ? "NULL" : sockaddr2string(to, NULL, 0));
585 
586    if (to != NULL && tolen != 0)
587       tolen = salen(to->ss_family);
588 
589    if (auth != NULL)
590       SASSERTX(authmethodisknown(auth->method));
591 
592    if (sendtoflags != NULL) {
593       sendtoflags->tosocket = 0;
594 
595 #if !SOCKS_CLIENT
596       SASSERTX(sendtoflags->side != NONESETIF);
597 #endif /* !SOCKS_CLIENT */
598    }
599 
600 #if HAVE_GSSAPI
601    if (auth != NULL
602    &&  auth->method == AUTHMETHOD_GSSAPI && auth->mdata.gssapi.state.wrap) {
603       written = gssapi_encode_write(s,
604                                     msg,
605                                     len,
606                                     flags,
607                                     to,
608                                     tolen,
609                                     sendtoflags,
610                                     &auth->mdata.gssapi.state);
611 
612       if (written == -1 && sendtoflags != NULL)
613          log_writefailed(sendtoflags->side, s, to);
614 
615       slog(LOG_DEBUG, "%s: gssapi-written on fd %d: %ld (%s)",
616            function, s, (long)written, strerror(errno));
617 
618       return written;
619    }
620 #endif
621 
622 #if SOCKS_CLIENT
623    /*
624     * no buffering is provided by us for the client, except if using gssapi,
625     * and that is handled in the above function.
626     */
627    if (to == NULL && flags == 0)
628       /* may not be a socket; write(2) will work just as well then. */
629       written = write(s, msg, len);
630    else
631       written = sendto(s, msg, len, flags, TOCSA(to), tolen);
632 
633    if (written != -1 && sendtoflags != NULL)
634       sendtoflags->tosocket = written;
635 
636    slog(LOG_DEBUG, "%s: written on fd %d: %ld", function, s, (long)written);
637 
638    return written;
639 #else /* !SOCKS_CLIENT */
640 
641    if ((towrite = socks_getfrombuffer(s, 0, WRITE_BUF, 0, buf, len)) > 0) {
642       /*
643        * already have data for write buffered.  Write that first, then
644        * append the new data, then possibly write the new data, but never
645        * write more than "len", even if we could due to data already
646        * buffered.  The reason not to write more includes fair sharing
647        * amongst clients.
648        *
649        * Also note that for the data buffered, we have already returned
650        * the byte count as written, so don't return it again, only return
651        * the count for new bytes added to the buffer.
652        */
653 
654       if (sockscf.option.debug >= DEBUG_VERBOSE)
655          slog(LOG_DEBUG,
656               "%s: got %lu byte%s from buffer, %lu bytes left in buffer",
657               function,
658               (unsigned long)towrite, towrite == 1 ? "" : "s",
659               (unsigned long)socks_bytesinbuffer(s, WRITE_BUF, 0));
660 
661       written_fb = sendto(s, buf, (size_t)towrite, flags, TOCSA(to), tolen);
662 
663       if (sendtoflags != NULL) {
664          if (written_fb == -1)
665             log_writefailed(sendtoflags->side, s, to);
666          else
667             sendtoflags->tosocket += written_fb;
668       }
669 
670       if (written_fb < towrite) {
671          /*
672           *  need to add at least some back in the buffer.
673           */
674          const ssize_t addback = written_fb > 0 ?
675                                                  towrite - written_fb : towrite;
676 
677          if ((p = socks_addtobuffer(s,
678                                     WRITE_BUF,
679                                     0,
680                                     buf + (towrite - addback),
681                                     (size_t)addback)) != addback)
682             SERRX(p);
683       }
684 
685       /* can we write more on this call? */
686       if (written_fb == -1) { /* no. */
687          if (!ERRNOISTMP(errno))
688             return -1;
689 
690          /* else; non-fatal error.  Try to buffer the rest. */
691          towrite = 0;
692       }
693       else { /* yes. */
694          towrite = len - written_fb;
695       }
696    }
697    else /* nothing buffered. */
698       towrite = len;
699 
700    if (towrite >= 0) { /* >= 0 because udp packets can be zero. */
701       /*
702        * try to also write some of the data passed us now.
703        */
704 
705       if ((written = sendto(s, msg, (size_t)towrite, flags, TOCSA(to), tolen))
706       == -1) {
707          iobuffer_t *iobuf;
708 
709          if (sendtoflags != NULL)
710             log_writefailed(sendtoflags->side, s, to);
711 
712          slog(LOG_DEBUG, "%s: %s(2) failed: %s",
713               function,
714               to == NULL && flags == 0 ? "write" : "sendto",
715               strerror(errno));
716 
717          /*
718           * If not permanent error, try to buffer the data, unless it's a
719           * udp socket, in which case we do not buffer.
720           */
721          if (!ERRNOISTMP(errno)
722          ||  (iobuf = socks_getbuffer(s)) == NULL
723          ||  iobuf->stype                 == SOCK_DGRAM)
724             return written;
725 
726          written = 0;
727       }
728    }
729    else
730       written = 0;
731 
732    if (sendtoflags != NULL)
733       sendtoflags->tosocket += written;
734 
735    SASSERTX(written <= (ssize_t)len);
736 
737    towrite = len - written;
738    if (towrite > 0) {
739       iobuffer_t *iobuf;
740       ssize_t written_tb;
741       int dobuffer;
742 
743       if ((iobuf = socks_getbuffer(s)) != NULL
744       &&  iobuf->stype                 != SOCK_DGRAM)
745          dobuffer = 1;
746       else
747          dobuffer = 0;
748 
749       if (sockscf.option.debug >= DEBUG_VERBOSE)
750          slog(LOG_DEBUG, "%s: %lu byte%s unwritten to socket.  %s",
751               function,
752               (unsigned long)towrite,
753               towrite == 1 ? "" : "s",
754               dobuffer ? "Adding to buffer" : "");
755 
756       if (!dobuffer)
757          return written;
758 
759       written_tb = socks_addtobuffer(s,
760                                      WRITE_BUF,
761                                      0,
762                                      (const char *)msg + written,
763                                      (size_t)towrite);
764       towrite -= written_tb;
765    }
766 
767    SASSERTX(towrite == 0);
768 
769    return len;
770 #endif /* !SOCKS_CLIENT */
771 }
772 
773 ssize_t
recvmsgn(s,msg,flags)774 recvmsgn(s, msg, flags)
775    int s;
776    struct msghdr *msg;
777    int flags;
778 {
779    const char *function = "recvmsgn()";
780    ssize_t received;
781 
782    if ((received = recvmsg(s, msg, flags)) == -1)
783       slog(LOG_DEBUG, "%s: recvmsg() on fd %d failed, received %ld bytes%s %s",
784            function,
785            s, (long)received,
786            sockscf.state.insignal ? "" : ":",
787            sockscf.state.insignal ? "" : strerror(errno));
788 
789    return received;
790 
791 #if 0
792    /*
793     * below code should not be used any longer since we only do recvmsg(2)
794     * on datagram sockets now.
795     */
796 
797    if (received <= 0)
798       return received;
799    left = len - (size_t)received;
800 
801    if (left > 0) {
802       size_t i, count, done;
803 
804       /*
805        * Can't call recvmsg() again since we could be getting ancillary data,
806        * read the elements one by one.
807        */
808 
809       SASSERTX(received >= 0);
810 
811       done = (size_t)received;
812       i = count = received = 0;
813       while (i < (size_t)msg->msg_iovlen && left > 0) {
814          const struct iovec *io = &msg->msg_iov[i];
815 
816          count += io->iov_len;
817          if (count > done) { /* didn't read all of this iovec. */
818             if ((received = socks_recvfromn(s,
819                         &((char *)(io->iov_base))[io->iov_len - (count - done)],
820                                             count - done,
821                                             count - done,
822                                             0,
823                                             NULL,
824                                             NULL,
825                                             NULL,
826                                             NULL,
827                                             NULL,
828                                             NULL))
829             != ((ssize_t)(count - done))) {
830                /*
831                 * Failed to read all data, close any descriptors we
832                 * may have gotten then.
833                 */
834                size_t leaked;
835                int d;
836 
837                swarn("%s: %ld byte%s left",
838                function, (long)left, left == 1 ? "" : "s");
839 
840                for (leaked = 0;
841                CMSG_SPACE(leaked * sizeof(d)) < (size_t)CMSG_TOTLEN(*msg);
842                ++leaked) {
843                   CMSG_GETOBJECT(d, CMSG_CONTROLDATA(*msg), leaked * sizeof(d));
844                   close(d);
845                }
846 
847                break;
848             }
849 
850             left -= received;
851             done += received;
852          }
853 
854          ++i;
855       }
856    }
857 
858    if (left == len)
859       return received; /* nothing read. */
860    return len - left;
861 #endif
862 
863 }
864 
865 ssize_t
sendmsgn(s,msg,flags,timeoutms)866 sendmsgn(s, msg, flags, timeoutms)
867    int s;
868    const struct msghdr *msg;
869    int flags;
870    const time_t timeoutms;
871 {
872    const char *function = "sendmsgn()";
873    static fd_set *wset;
874    const int maxfailures = 10;
875    struct timeval timestart;
876    ssize_t p, sent;
877    size_t len;
878    int failedcount, sendmsg_errno;
879 
880 #if !SOCKS_CLIENT
881    if (sockscf.state.type == PROC_MOTHER)
882       /*
883        * if not, we may end up calling selectn(), and if a SIGCHLD is
884        * pending, we might end up trying to use the descriptor of a child
885        * that was removed by the sigchld handler, or worse.
886        */
887       SASSERTX(timeoutms == 0);
888 #endif /* !SOCKS_CLIENT */
889 
890    if (wset == NULL)
891       wset = allocate_maxsize_fdset();
892 
893 
894    failedcount = len = 0;
895    while ((sent = sendmsg(s, msg, flags)) == -1) {
896       struct timeval timeleft;
897       int doretry = (   ERRNOISTMP(errno)
898                      && ++failedcount < maxfailures
899                      && timeoutms != 0);
900 
901       sendmsg_errno = errno;
902 
903       if (len == 0)
904          for (p = 0; p < (ssize_t)msg->msg_iovlen; ++p)
905             len += msg->msg_iov[p].iov_len;
906 
907       if (doretry) {
908          const struct timeval max_timetouse = { 0, timeoutms * 1000 };
909          struct timeval timenow;
910 
911          if (failedcount == 1)
912             gettimeofday_monotonic(&timestart);
913 
914          if (timeoutms != -1) {
915             struct timeval timeused;
916 
917             gettimeofday_monotonic(&timenow);
918             timersub(&timenow, &timestart, &timeused);
919 
920             SASSERTX(timeused.tv_sec >= 0);
921 
922             timersub(&max_timetouse, &timeused, &timeleft);
923             if (timeleft.tv_sec < 0)
924                doretry = 0;
925          }
926       }
927 
928       slog(LOG_DEBUG,
929            "%s: sendmsg() of %ld bytes on fd %d failed on try #%d (%s)%s",
930            function,
931            (long)len,
932            s,
933            failedcount,
934            strerror(errno),
935            doretry ? ".  Will block and retry" : ".  Giving up on this one");
936 
937       if (!doretry) {
938          if (errno == 0)
939             errno = sendmsg_errno;
940 
941          return -1;
942       }
943 
944       if (failedcount + 1 >= maxfailures) {
945          if (timeoutms == -1) {
946             /*
947              * even if there is no timeout, we don't want to block forever.
948              * Report the error and go to the next message.
949              */
950             timeleft.tv_sec  = 1;
951             timeleft.tv_usec = 0;
952          }
953 
954          slog(LOG_DEBUG,
955               "%s: failed %d times already.  Next retry is the last one, "
956               "so pausing for %ld.%06lds, hoping the message will get "
957               "through afterwards",
958               function,
959               failedcount,
960               (long)timeleft.tv_sec,
961               (long)timeleft.tv_usec);
962 
963          if ((p = selectn(0, NULL, NULL, NULL, NULL, NULL, &timeleft)) <= 0) {
964             slog(LOG_DEBUG, "%s: select() returned %ld, with time %ld.%06ld",
965                  function,
966                  (long)p,
967                  (long)timeleft.tv_sec,
968                  (long)timeleft.tv_usec);
969 
970             if (errno == 0)
971                errno = sendmsg_errno;
972 
973             return -1;
974          }
975 
976          continue;
977       }
978 
979       FD_ZERO(wset);
980       FD_SET(s, wset);
981       p = selectn(s + 1,
982                   NULL,
983                   NULL,
984                   NULL,
985                   wset,
986                   NULL,
987                   timeoutms == -1 ? NULL : &timeleft);
988 
989       if (timeoutms == -1)
990          slog(LOG_DEBUG, "%s: select() returned %d", function, (int)p);
991       else
992          slog(LOG_DEBUG, "%s: select() returned %d, with time %ld.%06ld",
993               function, (int)p, (long)timeleft.tv_sec, (long)timeleft.tv_usec);
994 
995       if (p <= 0) {
996 #if SOCKS_CLIENT
997          if (errno == EINTR) {
998             if (sockscf.state.handledsignal) {
999               /*
1000                * Can't know for sure, but assume we were interrupted due
1001                * to a signal from our own non-blocking connect child,
1002                * presumably signalling a connect(2) unrelated to this socket
1003                * has completed.
1004                */
1005                slog(LOG_DEBUG,
1006                     "%s: select(2) was interrupted, but looks like it could "
1007                     "be due to our own signal (signal #%d/%s), so assume we "
1008                     "should retry",
1009                     function,
1010                     (int)sockscf.state.handledsignal,
1011                     signal2string(sockscf.state.handledsignal));
1012 
1013                sockscf.state.handledsignal = 0;
1014                continue;
1015             }
1016          }
1017 #endif /* SOCKS_CLIENT */
1018 
1019          if (errno == 0)
1020             errno = sendmsg_errno;
1021 
1022          return -1;
1023       }
1024    }
1025 
1026    return sent;
1027 }
1028 
1029 int
selectn(nfds,rset,bufrset,buffwset,wset,xset,_timeout)1030 selectn(nfds, rset, bufrset, buffwset, wset, xset, _timeout)
1031    int nfds;
1032    fd_set *rset;
1033    fd_set *bufrset;
1034    fd_set *buffwset;
1035    fd_set *wset;
1036    fd_set *xset;
1037    struct timeval *_timeout;
1038 {
1039    const char *function = "selectn()";
1040    struct timespec *timeout, timeout_mem, zerotimeout = { 0, 0 };
1041    int i, rc, bufset_nfds;
1042 #if !SOCKS_CLIENT
1043    sigset_t fullmask;
1044 #endif /* !SOCKS_CLIENT */
1045    sigset_t oldmask;
1046 
1047 #if DIAGNOSTIC && !SOCKS_CLIENT
1048    static struct timeval tfirstshortsleep;
1049    static size_t shortsleepc;
1050    static fd_set *zeroset;
1051    /*
1052     * These constants are undoubtedly too lenient for some cpus, and
1053     * too strict for other cpu's, but this is what there is for now.
1054     */
1055    const struct timeval tshortsleep     = { 0, 2 },
1056                         tshorttimelapse = { 0, 100000 };
1057    const  size_t        maxshortsleepc  = 1000;
1058    struct timeval tstart, tend, tdiff;
1059 
1060    if (zeroset == NULL) {
1061       zeroset = allocate_maxsize_fdset();
1062       FD_ZERO(zeroset);
1063    }
1064 
1065    SASSERTX (_timeout  != NULL
1066    ||        (rset     != NULL && FD_CMP(zeroset, rset)     != 0)
1067    ||        (wset     != NULL && FD_CMP(zeroset, wset)     != 0)
1068    ||        (xset     != NULL && FD_CMP(zeroset, xset)     != 0));
1069 #endif /* DIAGNOSTIC && !SOCKS_CLIENT */
1070 
1071 #if DO_SHMEMCHECK
1072    shmemcheck();
1073 #endif /* DO_SHMEMCHECK */
1074 
1075    /* convert form select(2) timeval to pselect(3) timespec. */
1076    if (_timeout == NULL)
1077       timeout = NULL;
1078    else {
1079 #if HAVE_SELECT_MAXTIMEOUT
1080       struct timeval maxtimeout = { HAVE_SELECT_MAXTIMEOUT, 0 };
1081 
1082       if (timercmp(_timeout, &maxtimeout, >))
1083          *_timeout = maxtimeout;
1084 #endif /* HAVE_SELECT_MAXTIMEOUT */
1085 
1086 #if !SOCKS_CLIENT
1087       if (_timeout->tv_sec < 0) {
1088          SWARNX(_timeout->tv_sec);
1089          _timeout->tv_sec = 0;
1090       }
1091 
1092       if (_timeout->tv_usec < 0) {
1093          SWARNX(_timeout->tv_usec);
1094          _timeout->tv_usec = 0;
1095       }
1096 #endif /* !SOCKS_CLIENT */
1097 
1098       timeout = &timeout_mem;
1099       timeout->tv_sec  = _timeout->tv_sec;
1100       timeout->tv_nsec = _timeout->tv_usec * 1000;
1101    }
1102 
1103 #if SOCKS_CLIENT
1104    if (sockscf.connectchild != 0) { /* we are the mother process. */
1105       /*
1106        * Once there was a bug,
1107        * and SIGIO was blocked,
1108        * but we need SIGIO,
1109        * need it for non-blocking connects,
1110        * and the bug,
1111        * it made us fall asleep,
1112        * and no-one woke us up,
1113        * never ever again.
1114        */
1115 
1116 
1117       if (sigprocmask(SIG_SETMASK, NULL, &oldmask) != 0)
1118          serr("%s: sigprocmask() failed", function);
1119 
1120       SASSERTX(!sigismember(&oldmask, SIGIO));
1121    }
1122 
1123 #else /* !SOCKS_CLIENT */
1124 
1125    sigfillset(&fullmask);
1126 
1127    /*
1128     * Block any new signals until we call pselect(2) to avoid race conditions
1129     * between checking for pending signals with sockd_handledsignals()
1130     * and the pselect(2) call.  If not, signals received in that timeframe
1131     * will not be handled till after the pselect(2) returns naturally, but we
1132     * want to them to interrupt pselect(2) instead.
1133     */
1134    if (sigprocmask(SIG_BLOCK, &fullmask, &oldmask) != 0)
1135       SERR(errno);
1136 
1137    if (sockd_handledsignals() != 0) {
1138       /*
1139        * When mother gets a signal (e.g., SIGHUP or SIGCHLD), it's possible
1140        * to add or remove descriptors.  It is thus not safe to continue with
1141        * the descriptor set we get passed (could get e.g, EBADF); we must
1142        * return and let caller regenerate the fd_set's.
1143        */
1144 
1145       if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0)
1146          SERR(errno);
1147 
1148       errno = EINTR;
1149       return -1;
1150    }
1151 #endif /* !SOCKS_CLIENT */
1152 
1153    if (sockscf.option.debug >= DEBUG_VERBOSE) {
1154       char buf[1024];
1155       size_t bufused;
1156       int i;
1157 
1158       bufused = 0;
1159       for (i = 1, bufused = 0; i < SOCKS_NSIG; ++i) {
1160          if ((rc = sigismember(&oldmask, i)) == 1)
1161             bufused += snprintf(&buf[bufused], sizeof(buf) - bufused,
1162                                 "%d, ", i);
1163          else if (rc == -1)
1164             /*
1165              * May happen if SOCKS_NSIG is overdimensioned to accommodate
1166              * possible future increases in the kernel, without an
1167              * accompanying Dante recompile.
1168              */
1169             break; /* no more valid signals in range. */
1170       }
1171 
1172       if (bufused != 0)
1173          slog(LOG_DEBUG, "%s: signals blocked in oldmask: %s", function, buf);
1174 
1175       print_selectfds("pre-select:",
1176                       SOCKS_CLIENT ? 0 : 1,
1177                       nfds,
1178                       rset,
1179                       bufrset,
1180                       buffwset,
1181                       wset,
1182                       xset,
1183                       timeout);
1184    }
1185 
1186    bufset_nfds = 0;
1187    if (bufrset != NULL || buffwset != NULL) {
1188       /*
1189        * We need to go through each descriptor and see if it
1190        * has data buffered ready for reading.  If so, that descriptor
1191        * needs to also be set on return from the below select(2),
1192        * and the timeout must be zero (already have at least one
1193        * descriptor readable).
1194        */
1195       for (i = 0; i < nfds; ++i) {
1196          /*
1197           * Does the fd has data buffered for reading?
1198           * Should only check for decoded data on read.  If it's not
1199           * decoded, it means we were unable to read the whole token
1200           * last time, which means there is no data we can fetch from
1201           * the buffer until the rest of the token has been read from
1202           * the socket.
1203           */
1204          if (bufrset != NULL) {
1205             if (FD_ISSET(i, bufrset)
1206             &&  socks_bytesinbuffer(i, READ_BUF, 0) > 0) {
1207                if (sockscf.option.debug >= DEBUG_VERBOSE)
1208                   slog(LOG_DEBUG,
1209                        "%s: marking fd %d as having data buffered for read; "
1210                        "%lu + %lu bytes buffered for read, %lu + %lu for write",
1211                        function, i,
1212                        (long unsigned)socks_bytesinbuffer(i, READ_BUF, 0),
1213                        (long unsigned)socks_bytesinbuffer(i, READ_BUF, 1),
1214                        (long unsigned)socks_bytesinbuffer(i, WRITE_BUF, 0),
1215                        (long unsigned)socks_bytesinbuffer(i, WRITE_BUF, 1));
1216 
1217                FD_SET(i, bufrset);
1218                bufset_nfds = MAX(bufset_nfds, i + 1);
1219                timeout     = &zerotimeout;
1220             }
1221             else
1222                FD_CLR(i, bufrset);
1223          }
1224 
1225          /*
1226           * does the fd have data buffered for write?
1227           */
1228          if (buffwset != NULL) {
1229             if (FD_ISSET(i, buffwset)
1230             && socks_bufferhasbytes(i, WRITE_BUF) > 0) {
1231                if (sockscf.option.debug >= DEBUG_VERBOSE)
1232                   slog(LOG_DEBUG,
1233                        "%s: marking fd %d as having data buffered for write; "
1234                        "%lu + %lu bytes buffered for read, %lu + %lu for write",
1235                        function, i,
1236                        (long unsigned)socks_bytesinbuffer(i, READ_BUF, 0),
1237                        (long unsigned)socks_bytesinbuffer(i, READ_BUF, 1),
1238                        (long unsigned)socks_bytesinbuffer(i, WRITE_BUF, 0),
1239                        (long unsigned)socks_bytesinbuffer(i, WRITE_BUF, 1));
1240 
1241                FD_SET(i, buffwset);
1242                bufset_nfds = MAX(bufset_nfds, i + 1);
1243                timeout     = &zerotimeout;
1244             }
1245             else
1246                FD_CLR(i, buffwset);
1247          }
1248       }
1249    }
1250 
1251 #if DO_SHMEMCHECK
1252    shmemcheck();
1253 #endif /* DO_SHMEMCHECK */
1254 
1255    errno = 0; /* clear any old garbage. */
1256 
1257 
1258 #if DIAGNOSTIC && !SOCKS_CLIENT
1259    gettimeofday(&tstart, NULL);
1260 #endif /* DIAGNOSTIC && !SOCKS_CLIENT */
1261 
1262    rc = pselect(nfds,
1263                 rset,
1264                 wset,
1265                 xset,
1266                 timeout,
1267 #if SOCKS_CLIENT
1268                 NULL
1269 #else /* !SOCKS_CLIENT */
1270                 &oldmask
1271 #endif /* !SOCKS_CLIENT */
1272                );
1273 
1274 #if DIAGNOSTIC && !SOCKS_CLIENT
1275    gettimeofday(&tend, NULL);
1276 
1277    timersub(&tend, &tstart, &tdiff);
1278 
1279    if (timercmp(&tdiff, &tshortsleep, >)) {
1280 #if 0
1281       if (shortsleepc > 0)
1282          slog(LOG_NOTICE,
1283               "%s: line %d.  resetting shortsleepc, currently %lu",
1284               function, __LINE__, (unsigned long)shortsleepc);
1285 #endif
1286 
1287       shortsleepc = 0;
1288    }
1289    else {
1290       if (shortsleepc++ == 0)
1291          tfirstshortsleep = tend;
1292    }
1293 
1294    if (shortsleepc >= maxshortsleepc) {
1295       timersub(&tend, &tfirstshortsleep, &tdiff);
1296 
1297       if (timercmp(&tdiff, &tshorttimelapse, <)) {
1298          swarnx("%s: pselect(2) blocked for less than %ld.%06lds %lu times "
1299                 "during last %ld.%06lds.  Looks like a busyloop-bug",
1300                 function,
1301                 (long)tshortsleep.tv_sec,
1302                 (long)tshortsleep.tv_usec,
1303                 (unsigned long)shortsleepc,
1304                 (long)tdiff.tv_sec,
1305                 (long)tdiff.tv_usec);
1306 
1307          SERRX(0);
1308       }
1309       else {
1310 #if 0
1311          if (shortsleepc > 0)
1312             slog(LOG_NOTICE,
1313                  "%s: line %d.  resetting shortsleepc, currently %lu",
1314                  function, __LINE__, (unsigned long)shortsleepc);
1315 #endif
1316          shortsleepc      = 0;
1317       }
1318    }
1319 #endif /* DIAGNOSTIC && !SOCKS_CLIENT */
1320 
1321    if (sockscf.option.debug >= DEBUG_VERBOSE) {
1322       const int errno_s = errno;
1323       char pfix[256];
1324 
1325       snprintf(pfix, sizeof(pfix), "post-select returned %d (errno: %s)",
1326                rc, strerror(errno));
1327 
1328       SASSERTX(errno_s == errno);
1329       print_selectfds(pfix,
1330                       SOCKS_CLIENT ? 0 : 1,
1331                       nfds,
1332                       rset,
1333                       bufrset,
1334                       buffwset,
1335                       wset,
1336                       xset,
1337                       timeout);
1338       SASSERTX(errno_s == errno);
1339    }
1340 
1341 #if !SOCKS_CLIENT
1342    if (rc == -1 && errno == EINTR)
1343       (void)sockd_handledsignals();
1344 
1345    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0)
1346       SERR(errno);
1347 #endif /* !SOCKS_CLIENT */
1348 
1349 #if DO_SHMEMCHECK
1350       shmemcheck();
1351 #endif /* DO_SHMEMCHECK */
1352 
1353    if (rc == -1)
1354       return rc;
1355 
1356    return MAX(rc, bufset_nfds);
1357 }
1358 
1359 
1360 static void
print_selectfds(preamble,docheck,nfds,rset,bufrset,buffwset,wset,xset,timeout)1361 print_selectfds(preamble, docheck,
1362                 nfds, rset, bufrset, buffwset, wset, xset, timeout)
1363    const char *preamble;
1364    const int docheck;
1365    const int nfds;
1366    fd_set *rset, *bufrset, *buffwset;
1367    fd_set *wset;
1368    fd_set *xset;
1369    const struct timespec *timeout;
1370 {
1371    const char *function = "print_selectfds()";
1372    const int errno_s = errno;
1373    char buf[32],
1374         rsetfd[8192 * sizeof("65535") - 1], bufrsetfd[sizeof(rsetfd)],
1375         buffwsetfd[sizeof(rsetfd)], wsetfd[sizeof(rsetfd)],
1376         xsetfd[sizeof(rsetfd)];
1377    size_t rsetfdi, bufrsetfdi, buffwsetfdi, wsetfdi, xsetfdi, rc;
1378    int i;
1379 
1380    if (timeout != NULL)
1381       snprintf(buf, sizeof(buf),
1382                "%ld.%06lds",
1383                (long)timeout->tv_sec, (long)timeout->tv_nsec);
1384    else
1385       snprintf(buf, sizeof(buf), "0x0");
1386 
1387    rsetfdi = bufrsetfdi = buffwsetfdi = wsetfdi = xsetfdi = 0;
1388    *rsetfd = *bufrsetfd = *buffwsetfd = *wsetfd = *xsetfd = NUL;
1389 
1390    for (i = 0; i < nfds; ++i) {
1391       if (rset != NULL && FD_ISSET(i, rset)) {
1392          rc = snprintf(&rsetfd[rsetfdi], sizeof(rsetfd) - rsetfdi,
1393                       "%d%s, ",
1394                       i, docheck ? (fdisopen(i) ? "" : "-invalid") : "");
1395          rsetfdi += rc;
1396       }
1397 
1398       if (bufrset != NULL && FD_ISSET(i, bufrset)) {
1399          rc = snprintf(&bufrsetfd[bufrsetfdi],
1400                        sizeof(bufrsetfd) - bufrsetfdi,
1401                        "%d%s, ",
1402                        i, docheck ? (fdisopen(i) ? "" : "-invalid") : "");
1403          bufrsetfdi += rc;
1404       }
1405 
1406       if (buffwset != NULL && FD_ISSET(i, buffwset)) {
1407          rc = snprintf(&buffwsetfd[buffwsetfdi],
1408                        sizeof(buffwsetfd) - buffwsetfdi,
1409                        "%d%s, ",
1410                        i, docheck ? (fdisopen(i) ? "" : "-invalid") : "");
1411 
1412          buffwsetfdi += rc;
1413       }
1414 
1415 
1416       if (wset != NULL && FD_ISSET(i, wset)) {
1417          rc = snprintf(&wsetfd[wsetfdi], sizeof(wsetfd) - wsetfdi,
1418                        "%d%s, ",
1419                        i, docheck ? (fdisopen(i) ? "" : "-invalid") : "");
1420 
1421          wsetfdi += rc;
1422       }
1423 
1424       if (xset != NULL && FD_ISSET(i, xset)) {
1425          rc = snprintf(&xsetfd[xsetfdi], sizeof(xsetfd) - xsetfdi,
1426                        "%d%s, ",
1427                        i, docheck ? (fdisopen(i) ? "" : "-invalid") : "");
1428 
1429          xsetfdi += rc;
1430       }
1431    }
1432 
1433    slog(LOG_DEBUG,
1434         "%s nfds = %d, "
1435         "rset = %p (%s), "
1436         "bufrset = %p (%s), "
1437         "buffwset = %p (%s), "
1438         "wset = %p (%s), "
1439         "xset = %p (%s), "
1440         "timeout = %s",
1441         preamble, nfds,
1442         rset, rsetfd,
1443         bufrset, bufrsetfd,
1444         buffwset, buffwsetfd,
1445         wset, wsetfd,
1446         xset, xsetfd,
1447         buf);
1448 
1449    if (errno != errno_s) {
1450       swarnx("%s: strange ... errno changed from %d to %d",
1451       function, errno_s, errno);
1452 
1453       errno = errno_s;
1454    }
1455 }
1456