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