1#include "tunala.h"
2
3#ifndef NO_BUFFER
4
5void buffer_init(buffer_t * buf)
6{
7    buf->used = 0;
8    buf->total_in = buf->total_out = 0;
9}
10
11void buffer_close(buffer_t * buf)
12{
13    /* Our data is static - nothing needs "release", just reset it */
14    buf->used = 0;
15}
16
17/* Code these simple ones in compact form */
18unsigned int buffer_used(buffer_t * buf)
19{
20    return buf->used;
21}
22
23unsigned int buffer_unused(buffer_t * buf)
24{
25    return (MAX_DATA_SIZE - buf->used);
26}
27
28int buffer_full(buffer_t * buf)
29{
30    return (buf->used == MAX_DATA_SIZE ? 1 : 0);
31}
32
33int buffer_notfull(buffer_t * buf)
34{
35    return (buf->used < MAX_DATA_SIZE ? 1 : 0);
36}
37
38int buffer_empty(buffer_t * buf)
39{
40    return (buf->used == 0 ? 1 : 0);
41}
42
43int buffer_notempty(buffer_t * buf)
44{
45    return (buf->used > 0 ? 1 : 0);
46}
47
48unsigned long buffer_total_in(buffer_t * buf)
49{
50    return buf->total_in;
51}
52
53unsigned long buffer_total_out(buffer_t * buf)
54{
55    return buf->total_out;
56}
57
58/*
59 * These 3 static (internal) functions don't adjust the "total" variables as
60 * it's not sure when they're called how it should be interpreted. Only the
61 * higher-level "buffer_[to|from]_[fd|SSL|BIO]" functions should alter these
62 * values.
63 */
64# if 0                          /* To avoid "unused" warnings */
65static unsigned int buffer_adddata(buffer_t * buf, const unsigned char *ptr,
66                                   unsigned int size)
67{
68    unsigned int added = MAX_DATA_SIZE - buf->used;
69    if (added > size)
70        added = size;
71    if (added == 0)
72        return 0;
73    memcpy(buf->data + buf->used, ptr, added);
74    buf->used += added;
75    buf->total_in += added;
76    return added;
77}
78
79static unsigned int buffer_tobuffer(buffer_t * to, buffer_t * from, int cap)
80{
81    unsigned int moved, tomove = from->used;
82    if ((int)tomove > cap)
83        tomove = cap;
84    if (tomove == 0)
85        return 0;
86    moved = buffer_adddata(to, from->data, tomove);
87    if (moved == 0)
88        return 0;
89    buffer_takedata(from, NULL, moved);
90    return moved;
91}
92# endif
93
94static unsigned int buffer_takedata(buffer_t * buf, unsigned char *ptr,
95                                    unsigned int size)
96{
97    unsigned int taken = buf->used;
98    if (taken > size)
99        taken = size;
100    if (taken == 0)
101        return 0;
102    if (ptr)
103        memcpy(ptr, buf->data, taken);
104    buf->used -= taken;
105    /* Do we have to scroll? */
106    if (buf->used > 0)
107        memmove(buf->data, buf->data + taken, buf->used);
108    return taken;
109}
110
111# ifndef NO_IP
112
113int buffer_from_fd(buffer_t * buf, int fd)
114{
115    int toread = buffer_unused(buf);
116    if (toread == 0)
117        /* Shouldn't be called in this case! */
118        abort();
119    toread = read(fd, buf->data + buf->used, toread);
120    if (toread > 0) {
121        buf->used += toread;
122        buf->total_in += toread;
123    }
124    return toread;
125}
126
127int buffer_to_fd(buffer_t * buf, int fd)
128{
129    int towrite = buffer_used(buf);
130    if (towrite == 0)
131        /* Shouldn't be called in this case! */
132        abort();
133    towrite = write(fd, buf->data, towrite);
134    if (towrite > 0) {
135        buffer_takedata(buf, NULL, towrite);
136        buf->total_out += towrite;
137    }
138    return towrite;
139}
140
141# endif                         /* !defined(NO_IP) */
142
143# ifndef NO_OPENSSL
144
145static void int_ssl_check(SSL *s, int ret)
146{
147    int e = SSL_get_error(s, ret);
148    switch (e) {
149        /*
150         * These seem to be harmless and already "dealt with" by our
151         * non-blocking environment. NB: "ZERO_RETURN" is the clean "error"
152         * indicating a successfully closed SSL tunnel. We let this happen
153         * because our IO loop should not appear to have broken on this
154         * condition - and outside the IO loop, the "shutdown" state is
155         * checked.
156         */
157    case SSL_ERROR_NONE:
158    case SSL_ERROR_WANT_READ:
159    case SSL_ERROR_WANT_WRITE:
160    case SSL_ERROR_WANT_X509_LOOKUP:
161    case SSL_ERROR_ZERO_RETURN:
162        return;
163        /*
164         * These seem to be indications of a genuine error that should result
165         * in the SSL tunnel being regarded as "dead".
166         */
167    case SSL_ERROR_SYSCALL:
168    case SSL_ERROR_SSL:
169        SSL_set_app_data(s, (char *)1);
170        return;
171    default:
172        break;
173    }
174    /*
175     * For any other errors that (a) exist, and (b) crop up - we need to
176     * interpret what to do with them - so "politely inform" the caller that
177     * the code needs updating here.
178     */
179    abort();
180}
181
182void buffer_from_SSL(buffer_t * buf, SSL *ssl)
183{
184    int ret;
185    if (!ssl || buffer_full(buf))
186        return;
187    ret = SSL_read(ssl, buf->data + buf->used, buffer_unused(buf));
188    if (ret > 0) {
189        buf->used += ret;
190        buf->total_in += ret;
191    }
192    if (ret < 0)
193        int_ssl_check(ssl, ret);
194}
195
196void buffer_to_SSL(buffer_t * buf, SSL *ssl)
197{
198    int ret;
199    if (!ssl || buffer_empty(buf))
200        return;
201    ret = SSL_write(ssl, buf->data, buf->used);
202    if (ret > 0) {
203        buffer_takedata(buf, NULL, ret);
204        buf->total_out += ret;
205    }
206    if (ret < 0)
207        int_ssl_check(ssl, ret);
208}
209
210void buffer_from_BIO(buffer_t * buf, BIO *bio)
211{
212    int ret;
213    if (!bio || buffer_full(buf))
214        return;
215    ret = BIO_read(bio, buf->data + buf->used, buffer_unused(buf));
216    if (ret > 0) {
217        buf->used += ret;
218        buf->total_in += ret;
219    }
220}
221
222void buffer_to_BIO(buffer_t * buf, BIO *bio)
223{
224    int ret;
225    if (!bio || buffer_empty(buf))
226        return;
227    ret = BIO_write(bio, buf->data, buf->used);
228    if (ret > 0) {
229        buffer_takedata(buf, NULL, ret);
230        buf->total_out += ret;
231    }
232}
233
234# endif                         /* !defined(NO_OPENSSL) */
235
236#endif                          /* !defined(NO_BUFFER) */
237