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