1 /*
2  * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014
3  *      Inferno Nettverk A/S, Norway.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. The above copyright notice, this list of conditions and the following
9  *    disclaimer must appear in all copies of the software, derivative works
10  *    or modified versions, and any portions thereof, aswell as in all
11  *    supporting documentation.
12  * 2. All advertising materials mentioning features or use of this software
13  *    must display the following acknowledgement:
14  *      This product includes software developed by
15  *      Inferno Nettverk A/S, Norway.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * Inferno Nettverk A/S requests users of this software to return to
31  *
32  *  Software Distribution Coordinator  or  sdc@inet.no
33  *  Inferno Nettverk A/S
34  *  Oslo Research Park
35  *  Gaustadall�en 21
36  *  NO-0349 Oslo
37  *  Norway
38  *
39  * any improvements or extensions that they make and grant Inferno Nettverk A/S
40  * the rights to redistribute these changes.
41  *
42  */
43 
44 #include "common.h"
45 
46 static const char rcsid[] =
47 "$Id: iobuf.c,v 1.116.4.9 2014/08/15 18:16:41 karls Exp $";
48 
49 static int socks_flushallbuffers(void);
50 /*
51  * Flushes all buffers.
52  * Returns 0 if all were flushed successfully.
53  * Returns -1 if we failed to completely flush at least one buffer.
54  */
55 
56 #if !SOCKS_CLIENT
57 /*
58  * - Each negotiate child client can use one iobuffer for control.
59  * - Each request child and io child client can use one iobuffer for
60  *   control, src, and st.
61  */
62 static iobuffer_t
63    iobufv[MAX((SOCKD_NEGOTIATEMAX * 1  /* control */),
64                MAX((SOCKD_IOMAX   * 4  /* control, src, dst1, dst2. */),
65                     (SOCKD_REQUESTMAX   * 3  /* control, src, dst */)))];
66 static const size_t  iobufc = ELEMENTS(iobufv);
67 
68 #else /* SOCKS_CLIENT; allocate dynamically on per-need basis. */
69 static iobuffer_t *iobufv;
70 static size_t     iobufc;
71 #endif /* SOCKS_CLIENT */
72 
73 static size_t lastfreei;  /* last buffer freed, for quick allocation.  */
74 
75 void
socks_setbuffer(iobuf,mode,size)76 socks_setbuffer(iobuf, mode, size)
77    iobuffer_t *iobuf;
78    const int mode;
79    ssize_t size;
80 {
81 
82    iobuf->info[READ_BUF].mode  = _IONBF; /* only one supported for read. */
83    iobuf->info[WRITE_BUF].mode = mode;
84 
85    if (size == -1)
86       size = sizeof(*iobuf->buf);
87 
88    SASSERTX(size > 0);
89    SASSERTX(size <= (ssize_t)sizeof(*iobuf->buf));
90 
91    iobuf->info[READ_BUF].size  = size;
92    iobuf->info[WRITE_BUF].size = size;
93 }
94 
95 void
socks_setbufferfd(s,mode,size)96 socks_setbufferfd(s, mode, size)
97    const int s;
98    const int mode;
99    ssize_t size;
100 {
101    iobuffer_t *iobuf;
102 
103    SASSERTX(size <= SOCKD_BUFSIZE);
104 
105    if ((iobuf = socks_getbuffer(s)) == NULL)
106       return;
107 
108    socks_setbuffer(iobuf, mode, size);
109 }
110 
111 
112 int
socks_flushbuffer(s,len,sendtoflags)113 socks_flushbuffer(s, len, sendtoflags)
114    const int s;
115    const ssize_t len;
116    sendto_info_t *sendtoflags;
117 {
118    const char *function = "socks_flushbuffer()";
119 #if HAVE_GSSAPI || !SOCKS_CLIENT
120    unsigned char inputmem[sizeof(iobuffer_t)];
121    ssize_t written = 0;
122    ssize_t p;
123 #endif /* HAVE_GSSAPI || !SOCKS_CLIENT */
124 #if !SOCKS_CLIENT
125    int encoded;
126 #endif /* !SOCKS_CLIENT */
127 
128    if (sockscf.option.debug >= DEBUG_VERBOSE)
129       slog(LOG_DEBUG, "%s: fd %d, len = %ld", function, s, (long)len);
130 
131    if (sendtoflags != NULL)
132       sendtoflags->tosocket = 0;
133 
134    if (s == -1)
135       return socks_flushallbuffers();
136 
137    if (!socks_bufferhasbytes(s, WRITE_BUF))
138       return 0;
139 
140    slog(LOG_DEBUG, "%s: buffer for fd %d has bytes (%lu + %lu).  Flushing",
141         function,
142         s,
143         (unsigned long)socks_bytesinbuffer(s, WRITE_BUF, 0),
144         (unsigned long)socks_bytesinbuffer(s, WRITE_BUF, 1));
145 
146 
147 #if SOCKS_CLIENT
148 #if HAVE_GSSAPI
149    /*
150     * Note that we only use the iobuffer in the client if we are doing
151     * gssapi i/o, never for ordinary i/o.  For the server, it is used
152     * for both ordinary and gssapi-based i/o.
153     *
154     * In the client-case, we don't want to encode the packet on
155     * every buffered write.  E.g. we don't want 100 putc(3)'s to
156     * end up creating 100 gssapi-encoded one-byte packets.
157     * We therefore postpone encoding til we get a flush call, then
158     * encode the data we have, and write it as one token.
159     * That means any already encoded data in the buffer must be written
160     * before the unencoded data.
161     */
162 
163    SASSERTX(len == -1);
164 
165 again:
166    if (socks_bytesinbuffer(s, WRITE_BUF, 1) > 0) {
167       /*
168        * First we just peek, then we re-get what we actually managed
169        * to write to the socket, so we do not have to put what we could not
170        * write back into the buffer (which would be more complicated).
171        */
172       size_t towrite = socks_getfrombuffer(s,
173                                            MSG_PEEK,
174                                            WRITE_BUF,
175                                            1,
176                                            inputmem,
177                                            sizeof(inputmem));
178 
179       if (sockscf.option.debug >= DEBUG_VERBOSE)
180          slog(LOG_DEBUG,
181               "%s: attempting to flush %lu previously encoded byte%s ...",
182               function, (long unsigned)towrite, towrite == 1 ? "" : "s");
183 
184       p = write(s, inputmem, towrite);
185 
186       slog(LOG_DEBUG, "%s: write of %lu bytes returned %ld (%s)",
187            function, (unsigned long)towrite, (long)p, strerror(errno));
188 
189       if (p > 0) {
190          /*
191           * Before we just peeked at our own buffer.  Now re-get what we
192           * actually managed to write.
193           */
194 
195          written += p;
196 
197          socks_getfrombuffer(s, 0, WRITE_BUF, 1, inputmem, p);
198 
199          if (sendtoflags != NULL)
200             sendtoflags->tosocket += p;
201 
202          if (p != (ssize_t)towrite) {
203             /*
204              * No error, just did not manage to flush the whole buffer at
205              * this time.  As far as the client is concerned this is
206              * identical to an EAGAIN error though
207              */
208             errno = EAGAIN;
209             return -1;
210          }
211       }
212       else /* some error. */
213          return p;
214    }
215 
216    SASSERTX(socks_bytesinbuffer(s, WRITE_BUF, 1) == 0);
217 
218    while (socks_bytesinbuffer(s, WRITE_BUF, 0) > 0) {
219       /*
220        * Not yet encoded data in buffer, need to encode (and write) it too
221        * before we add any more to this buffer, to maintain order.
222        *
223        * Here we just encode what we have, then loop around to the start
224        * and try to write it.
225        */
226       gss_buffer_desc input_token, output_token;
227       socksfd_t socksfd, *ptr;
228       unsigned char outputmem[GSSAPI_HLEN + MAXGSSAPITOKENLEN];
229       unsigned short pshort;
230       ssize_t toencode;
231 
232       ptr = socks_getaddr(s, &socksfd, 1);
233       SASSERTX(ptr != NULL);
234       SASSERTX(socksfd.state.auth.method == AUTHMETHOD_GSSAPI);
235 
236       toencode
237       = socks_getfrombuffer(s,
238                             0,
239                             WRITE_BUF,
240                             0,
241                             inputmem,
242                             MIN(sizeof(inputmem),
243                              socksfd.state.auth.mdata.gssapi.state.maxgssdata));
244 
245       if (sockscf.option.debug >= DEBUG_VERBOSE)
246          slog(LOG_DEBUG, "%s: encoding %ld byte%s before flushing ...",
247               function, (long)toencode, toencode == 1 ? "" : "s");
248 
249       input_token.value  = inputmem;
250       input_token.length = toencode;
251 
252       output_token.value  = outputmem         + GSSAPI_HLEN;
253       output_token.length = sizeof(outputmem) - GSSAPI_HLEN;
254 
255       if (gssapi_encode(&input_token,
256                         &socksfd.state.auth.mdata.gssapi.state,
257                         &output_token) != 0) {
258          swarnx("%s: gssapi_encode() failed", function);
259          return -1;
260       }
261 
262       ((char *)(output_token.value))[GSSAPI_VERSION] = SOCKS_GSSAPI_VERSION;
263       ((char *)(output_token.value))[GSSAPI_STATUS]  = SOCKS_GSSAPI_PACKET;
264 
265       pshort = htons(output_token.length);
266       memcpy(&((char *)output_token.value)[GSSAPI_TOKEN_LENGTH],
267              &pshort,
268              sizeof(pshort));
269 
270       SASSERTX(GSSAPI_HLEN + output_token.length
271       <=       socks_freeinbuffer(s, WRITE_BUF));
272 
273       socks_addtobuffer(s,
274                         WRITE_BUF,
275                         1,
276                         output_token.value,
277                         output_token.length + GSSAPI_HLEN);
278    }
279 
280    if (socks_bytesinbuffer(s, WRITE_BUF, 1) > 0)
281       goto again;
282 
283    /*
284    * Else, nothing in buffers anymore, all flushed.
285    */
286 
287    SASSERTX(socks_bytesinbuffer(s, WRITE_BUF, 0) == 0);
288    SASSERTX(socks_bytesinbuffer(s, WRITE_BUF, 1) == 0);
289 
290    return 0;
291 
292 #else /* !HAVE_GSSAPI */
293 
294    return 0;
295 
296 #endif /* !HAVE_GSSAPI */
297 
298 #else /* !SOCKS_CLIENT */
299 
300    /*
301     * Server case is simpler.  If we are using gssapi on this socket,
302     * all data we have in the write buffer should be encoded already.
303     * If we are not using gssapi, none of it should be encoded.
304     */
305    if (socks_bytesinbuffer(s, WRITE_BUF, 0) > 0) {
306       SASSERTX(socks_bytesinbuffer(s, WRITE_BUF, 1) == 0);
307       encoded = 0;
308    }
309    else if (socks_bytesinbuffer(s, WRITE_BUF, 1) > 0) {
310       SASSERTX(socks_bytesinbuffer(s, WRITE_BUF, 0) == 0);
311       encoded = 1;
312    }
313    else
314       SERRX(0);
315 
316    do {
317       /*
318        * Fetch data from our buffer and try to write it.  First we just
319        * peek, and then we re-get what we actually managed to write to the
320        * socket.
321        *
322        * We want to keep writing while we can, but return at the first error,
323        * permanent or not.  This is in a loop to make sure errno is set
324        * correctly upon return if we fail to flush the whole buffer.
325        */
326       ssize_t rc;
327       size_t towrite;
328 
329       towrite = socks_getfrombuffer(s,
330                                     MSG_PEEK,
331                                     WRITE_BUF,
332                                     encoded,
333                                     inputmem,
334                                     len == -1 ? sizeof(inputmem) : (size_t)len);
335 
336       rc = write(s, inputmem, towrite);
337 
338       slog(LOG_DEBUG, "%s: wrote %ld/%ld %s bytes (%s)",
339            function,
340            (long)rc,
341            (long)towrite,
342            encoded ? "encoded" : "unencoded",
343            strerror(errno));
344 
345       if (rc > 0) {
346          /*
347           * Now get what we just peeked at before.
348           */
349          p = socks_getfrombuffer(s, 0, WRITE_BUF, encoded, inputmem, rc);
350          SASSERTX(p == rc);
351 
352          if (sendtoflags != NULL)
353             sendtoflags->tosocket += rc;
354       }
355       else
356          return -1;
357 
358       written += rc;
359    } while ((len == -1 || written < len)
360    && socks_bytesinbuffer(s, WRITE_BUF, encoded) > 0);
361 
362    SASSERTX(socks_bytesinbuffer(s, WRITE_BUF, 0) == 0);
363    SASSERTX(socks_bytesinbuffer(s, WRITE_BUF, 1) == 0);
364 
365    return written;
366 #endif /* !SOCKS_CLIENT */
367 }
368 
369 iobuffer_t *
socks_getbuffer(s)370 socks_getbuffer(s)
371    const int s;
372 {
373 /*   const char *function = "socks_getbuffer()";  */
374    static size_t i;
375 
376    if (i < iobufc && iobufv[i].s == s && iobufv[i].allocated)
377       return &iobufv[i];
378 
379    for (i = 0; i < iobufc; ++i)
380       if (iobufv[i].s == s && iobufv[i].allocated)
381          return &iobufv[i];
382 
383    return NULL;
384 }
385 
386 void
socks_clearbuffer(s,which)387 socks_clearbuffer(s, which)
388    const int s;
389    const whichbuf_t which;
390 {
391    iobuffer_t *iobuf;
392 
393    if ((iobuf = socks_getbuffer(s)) == NULL)
394       return;
395 
396    iobuf->info[which].len = iobuf->info[which].enclen = 0;
397 #if SOCKS_CLIENT
398    iobuf->info[which].readalready = 0;
399 #endif /* SOCKS_CLIENT */
400 
401    bzero(&iobuf->buf[which], sizeof(iobuf->buf[which]));
402 }
403 
404 iobuffer_t *
socks_allocbuffer(s,stype)405 socks_allocbuffer(s, stype)
406    const int s;
407    const int stype;
408 {
409    const char *function = "socks_allocbuffer()";
410 
411 #if SOCKS_CLIENT
412    sigset_t oset;
413 #endif /* SOCKS_CLIENT */
414    iobuffer_t *freebuffer;
415    size_t i;
416 
417    slog(LOG_DEBUG, "%s: fd %d, stype = %d", function, s, stype);
418 
419    SASSERTX(socks_getbuffer(s) == NULL);
420 
421    /*
422     * check if one of the already allocated ones is free.
423     */
424    if (lastfreei < iobufc && !iobufv[lastfreei].allocated)
425       freebuffer = &iobufv[lastfreei];
426    else {
427       for (i = 0, freebuffer = NULL; i < iobufc; ++i)
428          if (!iobufv[i].allocated) {
429             freebuffer = &iobufv[i];
430             break;
431          }
432    }
433 
434 #if SOCKS_CLIENT
435    /*
436     * for non-blocking connect, we get a SIGIO upon completion.
437     * We don't want that to happen during e.g. the below malloc(3) call,
438     * as the sigio handler may access the malloc-ed memory, or while
439     * we are in the processes of initializing this iobuf.
440     */
441    socks_sigblock(SIGIO, &oset);
442 
443    if (freebuffer == NULL) {
444       void *p;
445 
446       if ((p = realloc(iobufv, sizeof(*iobufv) * (iobufc + 1))) == NULL) {
447          swarn("%s: %s", function, NOMEM);
448          socks_sigunblock(&oset);
449 
450          return NULL;
451       }
452 
453       iobufv     = p;
454       iobufc     += 1;
455 
456       freebuffer = &iobufv[iobufc - 1];
457    }
458 #endif /* SOCKS_CLIENT */
459 
460    SASSERTX(freebuffer != NULL);
461    socks_initbuffer(s, stype, freebuffer);
462 
463 #if SOCKS_CLIENT
464    socks_sigunblock(&oset);
465 #endif /* SOCKS_CLIENT */
466 
467    return freebuffer;
468 }
469 
470 void
socks_initbuffer(fd,stype,iobuf)471 socks_initbuffer(fd, stype, iobuf)
472    const int fd;
473    const int stype;
474    iobuffer_t *iobuf;
475 {
476 
477    bzero(iobuf, sizeof(*iobuf));
478    iobuf->s         = fd;
479    iobuf->stype     = stype;
480    iobuf->allocated = 1;
481 
482    socks_setbuffer(iobuf, _IONBF, -1); /* default; no buffering. */
483 }
484 
485 
486 void
socks_reallocbuffer(old,new)487 socks_reallocbuffer(old, new)
488    const int old;
489    const int new;
490 {
491    const char *function = "socks_reallocbuffer()";
492    iobuffer_t *iobuf = socks_getbuffer(old);
493 
494    slog(LOG_DEBUG, "%s: old %d, new %d, %s",
495         function, old, new, iobuf == NULL ? "no iobuf" : "have iobuf");
496 
497    if (iobuf != NULL)
498       iobuf->s = new;
499 }
500 
501 void
socks_freebuffer(s)502 socks_freebuffer(s)
503    const int s;
504 {
505    const char *function = "socks_freebuffer()";
506 
507    slog(LOG_DEBUG, "%s: fd %d", function, s);
508 
509    if (lastfreei < iobufc
510    && iobufv[lastfreei].s == s && iobufv[lastfreei].allocated)
511       ;
512    else
513       lastfreei = 0;
514 
515    for (; lastfreei < iobufc; ++lastfreei) {
516       if (!iobufv[lastfreei].allocated
517       ||  iobufv[lastfreei].s != s)
518          continue;
519 
520       if (sockscf.option.debug >= DEBUG_VERBOSE
521       && ( socks_bufferhasbytes(s, READ_BUF)
522         || socks_bufferhasbytes(s, WRITE_BUF)))
523          slog(LOG_DEBUG, "%s: freeing buffer with data (%lu/%lu, %lu/%lu)",
524          function,
525          (unsigned long)socks_bytesinbuffer(s, READ_BUF, 0),
526          (unsigned long)socks_bytesinbuffer(s, READ_BUF, 1),
527          (unsigned long)socks_bytesinbuffer(s, WRITE_BUF, 0),
528          (unsigned long)socks_bytesinbuffer(s, WRITE_BUF, 1));
529 
530       iobufv[lastfreei].allocated = 0;
531       return;
532    }
533 }
534 
535 size_t
socks_addtobuffer(s,which,encoded,data,datalen)536 socks_addtobuffer(s, which, encoded, data, datalen)
537    const int s;
538    const whichbuf_t which;
539    const int encoded;
540    const void *data;
541    const size_t datalen;
542 {
543    const char *function = "socks_addtobuffer()";
544    iobuffer_t *iobuf;
545    size_t toadd, offset;
546 
547    if (datalen == 0)
548       return 0;
549 
550    iobuf = socks_getbuffer(s);
551    SASSERTX(iobuf != NULL);
552 
553    if (iobuf->stype == SOCK_DGRAM) { /* no buffering of udp for now. */
554       SASSERTX(socks_bufferhasbytes(s, READ_BUF)  == 0);
555       SASSERTX(socks_bufferhasbytes(s, WRITE_BUF) == 0);
556 
557       SERRX(0);
558    }
559 
560    toadd = MIN(socks_freeinbuffer(s, which), datalen);
561 
562    SASSERTX(toadd == datalen);
563 
564    if (encoded) {
565       /*
566        * appended to the end of encoded data, after any unencoded data.
567        */
568       offset =   socks_bytesinbuffer(s, which, 0)
569                + socks_bytesinbuffer(s, which, 1);
570    }
571    else {
572       /*
573        * more complex; appended to the end of the unencoded data,
574        * which comes before the encoded data.  Meaning we have to first
575        * move the encoded data further out in the buffer before we add the
576        * new unencoded data, so that that unencoded data we will add
577        * gets appended to any already present unencoded data, before
578        * the encoded data.
579        */
580 
581       memmove(&iobuf->buf[which][socks_bytesinbuffer(s, which, 0) + toadd],
582               &iobuf->buf[which][socks_bytesinbuffer(s, which, 0)],
583               socks_bytesinbuffer(s, which, 1));
584 
585       offset = socks_bytesinbuffer(s, which, 0);
586    }
587 
588    if (sockscf.option.debug >= DEBUG_VERBOSE && toadd >= 2) {
589       ssize_t p;
590 
591       p = (ssize_t)offset - 1;
592 
593       slog(LOG_DEBUG,
594            "%s: fd = %d, add %lu %s byte%s to %s buffer which currently has "
595            "%lu unencoded, %lu encoded.  Last bytes to add: 0x%x, 0x%x.  "
596            "Data will be added after byte 0x%x which is at offset %ld",
597            function,
598            s,
599            (unsigned long)datalen,
600            encoded ? "encoded" : "unencoded",
601            datalen == 1 ? "" : "s",
602            which == READ_BUF ? "read" : "write",
603            (unsigned long)socks_bytesinbuffer(s, which, 0),
604            (unsigned long)socks_bytesinbuffer(s, which, 1),
605            (int)((const unsigned char *)data)[datalen - 2],
606            (int)((const unsigned char *)data)[datalen - 1],
607            p > 0 ? (int)((const unsigned char *)iobuf->buf[which])[p] : 0,
608            (long)p);
609    }
610 
611    memcpy(&iobuf->buf[which][offset], data, toadd);
612 
613    if (encoded)
614       iobuf->info[which].enclen += toadd;
615    else
616       iobuf->info[which].len    += toadd;
617 
618    return toadd;
619 }
620 
621 size_t
socks_bytesinbuffer(s,which,encoded)622 socks_bytesinbuffer(s, which, encoded)
623    const int s;
624    const whichbuf_t which;
625    const int encoded;
626 {
627    const iobuffer_t *iobuf = socks_getbuffer(s);
628    size_t rc;
629 
630    if (iobuf == NULL)
631       return 0;
632 
633    if (encoded)
634       rc = iobuf->info[which].enclen;
635    else
636       rc = iobuf->info[which].len;
637 
638    SASSERTX(rc <= sizeof(iobuf->buf[which]));
639    return rc;
640 }
641 
642 size_t
socks_buffersize(s,which)643 socks_buffersize(s, which)
644    const int s;
645    const whichbuf_t which;
646 {
647    const iobuffer_t *iobuf = socks_getbuffer(s);
648 
649    if (iobuf == NULL)
650       return 0;
651 
652    return iobuf->info[which].size;
653 }
654 
655 
656 int
socks_bufferhasbytes(s,which)657 socks_bufferhasbytes(s, which)
658    const int s;
659    const whichbuf_t which;
660 {
661    const iobuffer_t *iobuf = socks_getbuffer(s);
662 
663    if (iobuf == NULL)
664       return 0;
665 
666    return iobuf->info[which].enclen || iobuf->info[which].len;
667 }
668 
669 
670 size_t
socks_freeinbuffer(s,which)671 socks_freeinbuffer(s, which)
672    const int s;
673    const whichbuf_t which;
674 {
675    const char *function = "socks_freeinbuffer()";
676    iobuffer_t *iobuf;
677    size_t rc;
678 
679    if ((iobuf = socks_getbuffer(s)) == NULL)
680       return 0;
681 
682    rc = iobuf->info[which].size
683         - (socks_bytesinbuffer(s, which, 0) + socks_bytesinbuffer(s, which, 1));
684 
685    if (sockscf.option.debug >= DEBUG_VERBOSE)
686       slog(LOG_DEBUG, "%s: fd %d, which %d, free: %lu",
687            function, s, which, (unsigned long)rc);
688 
689    SASSERTX(rc <= sizeof(iobuf->buf[which]));
690 
691    return rc;
692 }
693 
694 size_t
socks_getfrombuffer(s,flags,which,encoded,data,datalen)695 socks_getfrombuffer(s, flags, which, encoded, data, datalen)
696    const int s;
697    const size_t flags;
698    const whichbuf_t which;
699    const int encoded;
700    void *data;
701    const size_t datalen;
702 {
703    const char *function = "socks_getfrombuffer()";
704    iobuffer_t *iobuf;
705    size_t toget;
706 
707    if ((iobuf = socks_getbuffer(s)) == NULL)
708       return 0;
709 
710    if (sockscf.option.debug >= DEBUG_VERBOSE)
711       slog(LOG_DEBUG,
712            "%s: fd = %d, get up to %lu %s byte%s from %s buffer which "
713            "currently has %lu decoded, %lu encoded.  Flags = %lu",
714            function,
715            s,
716            (unsigned long)datalen,
717            encoded ? "encoded" : "decoded",
718            datalen == 1 ? "" : "s",
719            which == READ_BUF ? "read" : "write",
720            (unsigned long)socks_bytesinbuffer(s, which, 0),
721            (unsigned long)socks_bytesinbuffer(s, which, 1),
722            (unsigned long)flags);
723 
724    if ((toget = MIN(datalen, socks_bytesinbuffer(s, which, encoded))) == 0)
725       return 0;
726 
727    if (encoded) {
728       SASSERTX(iobuf->info[which].enclen >= toget);
729 
730       /* encoded data starts at the end of non-encoded data. */
731       memcpy(data, &iobuf->buf[which][iobuf->info[which].len], toget);
732 
733       if (!(flags & MSG_PEEK)) {
734          iobuf->info[which].enclen -= toget;
735 
736          /*
737           * encoded data stays at the end of unencoded data.
738           */
739          memmove(&iobuf->buf[which][iobuf->info[which].len],
740                  &iobuf->buf[which][iobuf->info[which].len + toget],
741                  iobuf->info[which].enclen);
742       }
743    }
744    else {
745       SASSERTX(iobuf->info[which].len >= toget);
746 
747       memcpy(data, iobuf->buf[which], toget);
748 
749       if (!(flags & MSG_PEEK)) {
750          iobuf->info[which].len -= toget;
751 
752          /* move the data remaining to the start of the buffer.  */
753          memmove(iobuf->buf[which],
754                  &iobuf->buf[which][toget],
755                  iobuf->info[which].len + iobuf->info[which].enclen);
756       }
757    }
758 
759    return toget;
760 }
761 
762 static int
socks_flushallbuffers(void)763 socks_flushallbuffers(void)
764 {
765 /*   const char *function = "socks_flushallbuffers()";  */
766    size_t i;
767    int rc;
768 
769    for (i = 0, rc = 0; i < iobufc; ++i)
770       if (iobufv[i].allocated)
771          if (socks_flushbuffer(iobufv[i].s, -1, NULL) == -1)
772             rc = -1;
773 
774    return rc;
775 }
776