* Fix a slight bug in the state-machine. This caused the client end of a
[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 }
9
10 void buffer_close(buffer_t *buf)
11 {
12         /* Our data is static - nothing needs "release", just reset */
13         buffer_init(buf);
14 }
15
16 /* Code these simple ones in compact form */
17 unsigned int buffer_used(buffer_t *buf) {
18         return buf->used; }
19 unsigned int buffer_unused(buffer_t *buf) {
20         return (MAX_DATA_SIZE - buf->used); }
21 int buffer_full(buffer_t *buf) {
22         return (buf->used == MAX_DATA_SIZE ? 1 : 0); }
23 int buffer_notfull(buffer_t *buf) {
24         return (buf->used < MAX_DATA_SIZE ? 1 : 0); }
25 int buffer_empty(buffer_t *buf) {
26         return (buf->used == 0 ? 1 : 0); }
27 int buffer_notempty(buffer_t *buf) {
28         return (buf->used > 0 ? 1 : 0); }
29
30 unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr,
31                 unsigned int size)
32 {
33         unsigned int added = MAX_DATA_SIZE - buf->used;
34         if(added > size)
35                 added = size;
36         if(added == 0)
37                 return 0;
38         memcpy(buf->data + buf->used, ptr, added);
39         buf->used += added;
40         return added;
41 }
42
43 unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr,
44                 unsigned int size)
45 {
46         unsigned int taken = buf->used;
47         if(taken > size)
48                 taken = size;
49         if(taken == 0)
50                 return 0;
51         if(ptr)
52                 memcpy(ptr, buf->data, taken);
53         buf->used -= taken;
54         /* Do we have to scroll? */
55         if(buf->used > 0)
56                 memmove(buf->data, buf->data + taken, buf->used);
57         return taken;
58 }
59
60 unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap)
61 {
62         unsigned int moved, tomove = from->used;
63         if((int)tomove > cap)
64                 tomove = cap;
65         if(tomove == 0)
66                 return 0;
67         moved = buffer_adddata(to, from->data, tomove);
68         if(moved == 0)
69                 return 0;
70         buffer_takedata(from, NULL, moved);
71         return moved;
72 }
73
74 #ifndef NO_IP
75
76 int buffer_from_fd(buffer_t *buf, int fd)
77 {
78         unsigned int toread = buffer_unused(buf);
79         if(toread == 0)
80                 /* Shouldn't be called in this case! */
81                 abort();
82         toread = read(fd, buf->data + buf->used, toread);
83         if(toread > 0)
84                 buf->used += toread;
85         return toread;
86 }
87
88 int buffer_to_fd(buffer_t *buf, int fd)
89 {
90         unsigned int towrite = buffer_used(buf);
91         if(towrite == 0)
92                 /* Shouldn't be called in this case! */
93                 abort();
94         towrite = write(fd, buf->data, towrite);
95         if(towrite > 0)
96                 buffer_takedata(buf, NULL, towrite);
97         return towrite;
98 }
99
100 #endif /* !defined(NO_IP) */
101
102 #ifndef NO_OPENSSL
103
104 static void int_ssl_check(SSL *s, int ret)
105 {
106         int e = SSL_get_error(s, ret);
107         switch(e) {
108                 /* These seem to be harmless and already "dealt with" by our
109                  * non-blocking environment. NB: "ZERO_RETURN" is the clean
110                  * "error" indicating a successfully closed SSL tunnel. We let
111                  * this happen because our IO loop should not appear to have
112                  * broken on this condition - and outside the IO loop, the
113                  * "shutdown" state is checked. */
114         case SSL_ERROR_NONE:
115         case SSL_ERROR_WANT_READ:
116         case SSL_ERROR_WANT_WRITE:
117         case SSL_ERROR_WANT_X509_LOOKUP:
118         case SSL_ERROR_ZERO_RETURN:
119                 return;
120                 /* These seem to be indications of a genuine error that should
121                  * result in the SSL tunnel being regarded as "dead". */
122         case SSL_ERROR_SYSCALL:
123         case SSL_ERROR_SSL:
124                 SSL_set_app_data(s, (char *)1);
125                 return;
126         default:
127                 break;
128         }
129         /* For any other errors that (a) exist, and (b) crop up - we need to
130          * interpret what to do with them - so "politely inform" the caller that
131          * the code needs updating here. */
132         abort();
133 }
134
135 void buffer_from_SSL(buffer_t *buf, SSL *ssl)
136 {
137         int ret;
138         if(!ssl || buffer_full(buf))
139                 return;
140         ret = SSL_read(ssl, buf->data + buf->used, buffer_unused(buf));
141         if(ret > 0)
142                 buf->used += ret;
143         if(ret < 0)
144                 int_ssl_check(ssl, ret);
145 }
146
147 void buffer_to_SSL(buffer_t *buf, SSL *ssl)
148 {
149         int ret;
150         if(!ssl || buffer_empty(buf))
151                 return;
152         ret = SSL_write(ssl, buf->data, buf->used);
153         if(ret > 0)
154                 buffer_takedata(buf, NULL, ret);
155         if(ret < 0)
156                 int_ssl_check(ssl, ret);
157 }
158
159 void buffer_from_BIO(buffer_t *buf, BIO *bio)
160 {
161         int ret;
162         if(!bio || buffer_full(buf))
163                 return;
164         ret = BIO_read(bio, buf->data + buf->used, buffer_unused(buf));
165         if(ret > 0)
166                 buf->used += ret;
167 }
168
169 void buffer_to_BIO(buffer_t *buf, BIO *bio)
170 {
171         int ret;
172         if(!bio || buffer_empty(buf))
173                 return;
174         ret = BIO_write(bio, buf->data, buf->used);
175         if(ret > 0)
176                 buffer_takedata(buf, NULL, ret);
177 }
178
179 #endif /* !defined(NO_OPENSSL) */
180
181 #endif /* !defined(NO_BUFFER) */