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