ucspi-ssl 0.13.03
ucspi-ssl
Loading...
Searching...
No Matches
ssl_io.c
Go to the documentation of this file.
1#include <unistd.h>
2#include <sys/types.h>
3#include <sys/socket.h>
4#include "iopause.h"
5#include "buffer.h"
6#include "taia.h"
7#include "ucspissl.h"
8#include "error.h"
9
10static int leftstatus = 0;
11static char leftbuf[16 * 1024];
12static int leftlen;
13static int leftpos;
14
15static int rightstatus = 0;
16static char rightbuf[16 * 1024];
17static int rightlen;
18static int rightpos;
19
20int ssl_io(SSL *ssl,int fdleft,int fdright,unsigned int timeout) {
21 struct taia now;
22 struct taia deadline;
23 iopause_fd x[4];
24 int xlen;
25 iopause_fd *io0;
26 iopause_fd *ioleft;
27 iopause_fd *io1;
28 iopause_fd *ioright;
29 int r;
30 int rc = 0;
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
58 ioleft = 0;
59 if (leftstatus == 1) {
60 ioleft = &x[xlen++];
61 ioleft->fd = fdleft;
62 ioleft->events = IOPAUSE_WRITE;
63 }
64
65 ioright = 0;
66 if (rightstatus == 0) {
67 ioright = &x[xlen++];
68 ioright->fd = fdright;
69 ioright->events = IOPAUSE_READ;
70 }
71
72 io1 = 0;
73 if (rightstatus == 1) {
74 io1 = &x[xlen++];
75 io1->fd = wfd;
76 io1->events = IOPAUSE_WRITE;
77 }
78
79 if (taia_now(&now) == -1) {
80 errno = ETIMEDOUT;
81 rc = -1;
82 goto BOMB;
83 }
84 taia_uint(&deadline,timeout);
85 taia_add(&deadline,&now,&deadline);
86 iopause(x,xlen,&deadline,&now);
87
88 for (r = 0; r < xlen; ++r)
89 if (x[r].revents) goto EVENTS;
90
91 if (io0 && !ssl_pending(ssl)) {
92 close(fdleft);
93 leftstatus = -1;
94 continue;
95 }
96 errno = ETIMEDOUT;
97 rc = -1;
98 goto BOMB;
99
100
101EVENTS:
102 if (io0 && io0->revents) {
103 r = SSL_read(ssl,leftbuf,sizeof(leftbuf));
104 ssl_errno = SSL_get_error(ssl,r);
105 switch (ssl_errno) {
106 case SSL_ERROR_NONE:
107 leftstatus = 1;
108 leftpos = 0;
109 leftlen = r;
110 break;
111 case SSL_ERROR_WANT_READ:
112 case SSL_ERROR_WANT_WRITE:
113 case SSL_ERROR_WANT_X509_LOOKUP:
114 break;
115 case SSL_ERROR_ZERO_RETURN:
116 if (rightstatus == -1) goto DONE;
117 close(fdleft);
118 leftstatus = -1;
119 break;
120 case SSL_ERROR_SYSCALL:
121 if (errno == EAGAIN || errno == EINTR) break;
122 close(fdleft);
123 leftstatus = -1;
124 if (!errno) break;
125 /* premature close */
126 if (errno == ECONNRESET && rightstatus == -1) goto DONE;
127 goto BOMB;
128 case SSL_ERROR_SSL:
129/* Continuing after a received SSL error given the socket is still
130 * potentially active might be a noble cause, but is impracticle.
131 * We consider an SSL_ERROR_SSL as application failure; not TLS
132 * and close the connection gracefully.
133 * if (errno == EAGAIN || errno == EINTR) break;
134 * if (!errno) break;
135 */
136 goto DONE;
137 default:
138 close(fdleft);
139 leftstatus = -1;
140 if (rightstatus == 1) break;
141 if (ssl_shutdown_pending(ssl)) goto DONE;
142 goto BOMB;
143 }
144 }
145
146 if (ioleft && ioleft->revents) {
147 r = buffer_unixwrite(fdleft,leftbuf + leftpos,leftlen - leftpos);
148 if (r == -1) {
149 if (errno == EINTR || errno == EWOULDBLOCK) {
150 /* retry */
151 }
152 else if (errno == EPIPE || errno == EAGAIN) {
153 if (rightstatus == -1) goto DONE;
154 close(fdleft);
155 leftstatus = -1;
156 } else {
157 rc = -1;
158 goto BOMB;
159 }
160 }
161 else {
162 leftpos += r;
163 if (leftpos == leftlen) {
164 leftstatus = 0;
165 if ((r = ssl_pending(ssl))) {
166 if (r > sizeof(leftbuf)) r = sizeof(leftbuf);
167 r = SSL_read(ssl,leftbuf,r);
168 ssl_errno = SSL_get_error(ssl,r);
169 switch (ssl_errno) {
170 case SSL_ERROR_NONE:
171 leftstatus = 1;
172 leftpos = 0;
173 leftlen = r;
174 break;
175 case SSL_ERROR_WANT_READ:
176 case SSL_ERROR_WANT_WRITE:
177 case SSL_ERROR_WANT_X509_LOOKUP:
178 break;
179 case SSL_ERROR_ZERO_RETURN:
180 if (rightstatus == -1) goto DONE;
181 close(fdleft);
182 leftstatus = -1;
183 break;
184 default:
185 rc = -1;
186 goto BOMB;
187 }
188 }
189 }
190 }
191 }
192
193 if (ioright && ioright->revents) {
194 r = buffer_unixread(fdright,rightbuf,sizeof(rightbuf));
195 if (r == -1) {
196 if (errno == EINTR || errno == EWOULDBLOCK) {
197 /* retry */
198 } else {
199 rc = -1;
200 goto BOMB; /* errno == EAGAIN => unrecoverable */
201 }
202 }
203 else if (r == 0) {
204 close(fdright);
205 rightstatus = -1;
206 if (ssl_shutdown(ssl)) goto DONE;
207 if (leftstatus == -1) goto DONE;
208 }
209 else {
210 rightstatus = 1;
211 rightpos = 0;
212 rightlen = r;
213 }
214 }
215
216 if (io1 && io1->revents) {
217 r = SSL_write(ssl,rightbuf + rightpos,rightlen - rightpos);
218 ssl_errno = SSL_get_error(ssl,r);
219 switch (ssl_errno) {
220 case SSL_ERROR_NONE:
221 rightpos += r;
222 if (rightpos == rightlen) rightstatus = 0;
223 break;
224 case SSL_ERROR_WANT_READ:
225 case SSL_ERROR_WANT_WRITE:
226 case SSL_ERROR_WANT_X509_LOOKUP:
227 break;
228 case SSL_ERROR_ZERO_RETURN:
229 close(fdright);
230 rightstatus = -1;
231 if (leftstatus == -1) goto DONE;
232 if (ssl_shutdown(ssl)) goto DONE;
233 break;
234 case SSL_ERROR_SYSCALL:
235 if (errno == EAGAIN || errno == EINTR) break;
236 if (errno == EPIPE) {
237 close(fdright);
238 rightstatus = -1;
239 if (leftstatus == -1) goto DONE;
240 if (ssl_shutdown(ssl)) goto DONE;
241 break;
242 }
243 default:
244 rc = -1;
245 goto BOMB;
246 }
247 }
248 }
249
250
251BOMB:
252 r = errno;
253 if (leftstatus != -1) close(fdleft);
254 if (rightstatus != -1) close(fdright);
255 if (!ssl_shutdown_sent(ssl)) ssl_shutdown(ssl);
256 if (!ssl_shutdown_pending(ssl)) ssl_shutdown(ssl);
257 shutdown(wfd,2);
258 errno = r;
259 return rc;
260
261
262DONE:
263 if (!ssl_shutdown_sent(ssl)) ssl_shutdown(ssl);
264 if (!ssl_shutdown_pending(ssl)) ssl_shutdown(ssl);
265 shutdown(wfd,2);
266 if (leftstatus != -1) close(fdleft);
267 if (rightstatus != -1) close(fdright);
268 return 0;
269}
int ssl_io(SSL *ssl, int fdleft, int fdright, unsigned int timeout)
Definition: ssl_io.c:20
unsigned long timeout
Definition: sslhandle.c:66
int ssl_errno
Definition: ucspissl.c:3
Header file to be used with sqmail; previously called ssl.h. (name clash)
#define ssl_pending(ssl)
Definition: ucspissl.h:65
#define ssl_shutdown_sent(ssl)
Definition: ucspissl.h:68
#define ssl_shutdown(ssl)
Definition: ucspissl.h:66
#define ssl_shutdown_pending(ssl)
Definition: ucspissl.h:67