1 #include "tunala.h"
2 
3 #ifndef NO_BUFFER
4 
5 void buffer_init(buffer_t *buf)
6 {
7 	buf->used = 0;
8 	buf->total_in = buf->total_out = 0;
9 }
10 
11 void 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 */
18 unsigned int buffer_used(buffer_t *buf) {
19 	return buf->used; }
20 unsigned int buffer_unused(buffer_t *buf) {
21 	return (MAX_DATA_SIZE - buf->used); }
22 int buffer_full(buffer_t *buf) {
23 	return (buf->used == MAX_DATA_SIZE ? 1 : 0); }
24 int buffer_notfull(buffer_t *buf) {
25 	return (buf->used < MAX_DATA_SIZE ? 1 : 0); }
26 int buffer_empty(buffer_t *buf) {
27 	return (buf->used == 0 ? 1 : 0); }
28 int buffer_notempty(buffer_t *buf) {
29 	return (buf->used > 0 ? 1 : 0); }
30 unsigned long buffer_total_in(buffer_t *buf) {
31 	return buf->total_in; }
32 unsigned 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 */
40 static 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 
54 static 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 
69 static 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 
88 int 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 
102 int 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 
120 static 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 
151 void 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 
165 void 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 
179 void 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 
191 void 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