1 #include <unistd.h>
2 #include <openssl/ssl.h>
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include "iopause.h"
6 #include "buffer.h"
7 #include "taia.h"
8 #include "ucspissl.h"
9 #include "error.h"
10
11 static int leftstatus = 0;
12 static char leftbuf[16 * 1024];
13 static int leftlen;
14 static int leftpos;
15
16 static int rightstatus = 0;
17 static char rightbuf[16 * 1024];
18 static int rightlen;
19 static int rightpos;
20
ssl_io(SSL * ssl,int fdleft,int fdright,unsigned int timeout)21 int ssl_io(SSL *ssl,int fdleft,int fdright,unsigned int timeout) {
22 struct taia now;
23 struct taia deadline;
24 iopause_fd x[4];
25 int xlen;
26 iopause_fd *io0;
27 iopause_fd *ioleft;
28 iopause_fd *io1;
29 iopause_fd *ioright;
30 int r;
31 int rfd;
32 int wfd;
33
34 rfd = SSL_get_fd(ssl); /* XXX */
35 if (rfd == -1) {
36 close(fdleft); close(fdright);
37 return -1;
38 }
39 wfd = SSL_get_fd(ssl); /* XXX */
40 if (wfd == -1) {
41 close(fdleft); close(fdright);
42 return -1;
43 }
44
45 for (;;) {
46 xlen = 0;
47
48 if (leftstatus == -1 && rightstatus == -1)
49 goto done;
50
51 io0 = 0;
52 if (leftstatus == 0 && rightstatus != 1) {
53 io0 = &x[xlen++];
54 io0->fd = rfd;
55 io0->events = IOPAUSE_READ;
56 }
57 ioleft = 0;
58 if (leftstatus == 1) {
59 ioleft = &x[xlen++];
60 ioleft->fd = fdleft;
61 ioleft->events = IOPAUSE_WRITE;
62 }
63
64 ioright = 0;
65 if (rightstatus == 0) {
66 ioright = &x[xlen++];
67 ioright->fd = fdright;
68 ioright->events = IOPAUSE_READ;
69 }
70 io1 = 0;
71 if (rightstatus == 1) {
72 io1 = &x[xlen++];
73 io1->fd = wfd;
74 io1->events = IOPAUSE_WRITE;
75 }
76
77 if (taia_now(&now) == -1) {
78 errno = error_timeout;
79 goto bomb;
80 }
81 taia_uint(&deadline,timeout);
82 taia_add(&deadline,&now,&deadline);
83 iopause(x,xlen,&deadline,&now);
84 for (r = 0;r < xlen;++r)
85 if (x[r].revents) goto events;
86
87 if (io0 && !ssl_pending(ssl)) {
88 close(fdleft);
89 leftstatus = -1;
90 continue;
91 }
92 errno = error_timeout;
93 goto bomb;
94
95 events:
96 if (io0 && io0->revents) {
97 r = SSL_read(ssl,leftbuf,sizeof leftbuf);
98 ssl_errno = SSL_get_error(ssl,r);
99 switch (ssl_errno) {
100 case SSL_ERROR_NONE:
101 leftstatus = 1;
102 leftpos = 0;
103 leftlen = r;
104 break;
105 case SSL_ERROR_WANT_READ:
106 case SSL_ERROR_WANT_WRITE:
107 case SSL_ERROR_WANT_X509_LOOKUP:
108 break;
109 case SSL_ERROR_ZERO_RETURN:
110 if (rightstatus == -1) goto done;
111 close(fdleft);
112 leftstatus = -1;
113 break;
114 case SSL_ERROR_SYSCALL:
115 if (errno == error_again || errno == error_intr) break;
116 close(fdleft);
117 leftstatus = -1;
118 if (!errno) break;
119 /* premature close */
120 if (errno == error_connreset && rightstatus == -1) goto done;
121 goto bomb;
122 case SSL_ERROR_SSL:
123 if (errno == error_again || errno == error_intr) break;
124 if (!errno) break;
125 goto bomb;
126 default:
127 close(fdleft);
128 leftstatus = -1;
129 if (rightstatus == 1) break;
130 if (ssl_shutdown_pending(ssl)) goto done;
131 goto bomb;
132 }
133 }
134
135 if (ioleft && ioleft->revents) {
136 r = buffer_unixwrite(fdleft,leftbuf + leftpos,leftlen - leftpos);
137 if (r == -1) {
138 if (errno == error_again || errno == error_intr || errno == error_wouldblock) {
139 /* retry */
140 }
141 else if (errno == error_pipe) {
142 if (rightstatus == -1) goto done;
143 close(fdleft);
144 leftstatus = -1;
145 }
146 else
147 goto bomb;
148 }
149 else {
150 leftpos += r;
151 if (leftpos == leftlen) {
152 leftstatus = 0;
153 if ((r = ssl_pending(ssl))) {
154 if (r > sizeof leftbuf) r = sizeof leftbuf;
155 r = SSL_read(ssl,leftbuf,r);
156 ssl_errno = SSL_get_error(ssl,r);
157 switch(ssl_errno) {
158 case SSL_ERROR_NONE:
159 leftstatus = 1;
160 leftpos = 0;
161 leftlen = r;
162 break;
163 case SSL_ERROR_WANT_READ:
164 case SSL_ERROR_WANT_WRITE:
165 case SSL_ERROR_WANT_X509_LOOKUP:
166 break;
167 case SSL_ERROR_ZERO_RETURN:
168 if (rightstatus == -1) goto done;
169 close(fdleft);
170 leftstatus = -1;
171 break;
172 default:
173 goto bomb;
174 }
175 }
176 }
177 }
178 }
179
180 if (ioright && ioright->revents) {
181 r = buffer_unixread(fdright,rightbuf,sizeof rightbuf);
182 if (r == -1) {
183 if (errno == error_again || errno == error_intr || errno == error_wouldblock) {
184 /* retry */
185 }
186 else
187 goto bomb;
188 }
189 else if (r == 0) {
190 close(fdright);
191 rightstatus = -1;
192 if (ssl_shutdown(ssl)) goto done;
193 if (leftstatus == -1) goto done;
194 }
195 else {
196 rightstatus = 1;
197 rightpos = 0;
198 rightlen = r;
199 }
200 }
201
202 if (io1 && io1->revents) {
203 r = SSL_write(ssl,rightbuf + rightpos,rightlen - rightpos);
204 ssl_errno = SSL_get_error(ssl,r);
205 switch (ssl_errno) {
206 case SSL_ERROR_NONE:
207 rightpos += r;
208 if (rightpos == rightlen) rightstatus = 0;
209 break;
210 case SSL_ERROR_WANT_READ:
211 case SSL_ERROR_WANT_WRITE:
212 case SSL_ERROR_WANT_X509_LOOKUP:
213 break;
214 case SSL_ERROR_ZERO_RETURN:
215 close(fdright);
216 rightstatus = -1;
217 if (leftstatus == -1) goto done;
218 if (ssl_shutdown(ssl)) goto done;
219 break;
220 case SSL_ERROR_SYSCALL:
221 if (errno == error_again || errno == error_intr) break;
222 if (errno == error_pipe) {
223 close(fdright);
224 rightstatus = -1;
225 if (leftstatus == -1) goto done;
226 if (ssl_shutdown(ssl)) goto done;
227 break;
228 }
229 default:
230 goto bomb;
231 }
232 }
233 }
234
235 bomb:
236 r = errno;
237 if (leftstatus != -1) close(fdleft);
238 if (rightstatus != -1) close(fdright);
239 if (!ssl_shutdown_sent(ssl)) ssl_shutdown(ssl);
240 if (!ssl_shutdown_pending(ssl)) ssl_shutdown(ssl);
241 shutdown(wfd,2);
242 errno = r;
243 return -1;
244
245 done:
246 if (!ssl_shutdown_sent(ssl)) ssl_shutdown(ssl);
247 if (!ssl_shutdown_pending(ssl)) ssl_shutdown(ssl);
248 shutdown(wfd,2);
249 if (leftstatus != -1) close(fdleft);
250 if (rightstatus != -1) close(fdright);
251 return 0;
252 }
253