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