1 /* $OpenBSD: evbuffer_tls.c,v 1.7 2015/09/10 18:32:06 bluhm Exp $ */ 2 3 /* 4 * Copyright (c) 2002-2004 Niels Provos <provos@citi.umich.edu> 5 * Copyright (c) 2014-2015 Alexander Bluhm <bluhm@openbsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/time.h> 33 #include <sys/ioctl.h> 34 35 #include <errno.h> 36 #include <event.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <tls.h> 41 42 #include "evbuffer_tls.h" 43 44 /* prototypes */ 45 46 void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *); 47 int evtls_read(struct evbuffer *, int, int, struct tls *); 48 int evtls_write(struct evbuffer *, int, struct tls *); 49 50 static int 51 bufferevent_add(struct event *ev, int timeout) 52 { 53 struct timeval tv, *ptv = NULL; 54 55 if (timeout) { 56 timerclear(&tv); 57 tv.tv_sec = timeout; 58 ptv = &tv; 59 } 60 61 return (event_add(ev, ptv)); 62 } 63 64 static void 65 buffertls_readcb(int fd, short event, void *arg) 66 { 67 struct buffertls *buftls = arg; 68 struct bufferevent *bufev = buftls->bt_bufev; 69 struct tls *ctx = buftls->bt_ctx; 70 int res = 0; 71 short what = EVBUFFER_READ; 72 size_t len; 73 int howmuch = -1; 74 75 if (event == EV_TIMEOUT) { 76 what |= EVBUFFER_TIMEOUT; 77 goto error; 78 } 79 80 /* 81 * If we have a high watermark configured then we don't want to 82 * read more data than would make us reach the watermark. 83 */ 84 if (bufev->wm_read.high != 0) { 85 howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input); 86 /* we might have lowered the watermark, stop reading */ 87 if (howmuch <= 0) { 88 struct evbuffer *buf = bufev->input; 89 event_del(&bufev->ev_read); 90 evbuffer_setcb(buf, 91 bufferevent_read_pressure_cb, bufev); 92 return; 93 } 94 } 95 96 res = evtls_read(bufev->input, fd, howmuch, ctx); 97 switch (res) { 98 case TLS_WANT_POLLIN: 99 event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, 100 buftls); 101 goto reschedule; 102 case TLS_WANT_POLLOUT: 103 event_set(&bufev->ev_read, fd, EV_WRITE, buffertls_readcb, 104 buftls); 105 goto reschedule; 106 case -1: 107 if (errno == EAGAIN || errno == EINTR) 108 goto reschedule; 109 /* error case */ 110 what |= EVBUFFER_ERROR; 111 break; 112 case 0: 113 /* eof case */ 114 what |= EVBUFFER_EOF; 115 break; 116 } 117 if (res <= 0) 118 goto error; 119 120 event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls); 121 bufferevent_add(&bufev->ev_read, bufev->timeout_read); 122 123 /* See if this callbacks meets the water marks */ 124 len = EVBUFFER_LENGTH(bufev->input); 125 if (bufev->wm_read.low != 0 && len < bufev->wm_read.low) 126 return; 127 if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) { 128 struct evbuffer *buf = bufev->input; 129 event_del(&bufev->ev_read); 130 131 /* Now schedule a callback for us when the buffer changes */ 132 evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); 133 } 134 135 /* Invoke the user callback - must always be called last */ 136 if (bufev->readcb != NULL) 137 (*bufev->readcb)(bufev, bufev->cbarg); 138 return; 139 140 reschedule: 141 bufferevent_add(&bufev->ev_read, bufev->timeout_read); 142 return; 143 144 error: 145 (*bufev->errorcb)(bufev, what, bufev->cbarg); 146 } 147 148 static void 149 buffertls_writecb(int fd, short event, void *arg) 150 { 151 struct buffertls *buftls = arg; 152 struct bufferevent *bufev = buftls->bt_bufev; 153 struct tls *ctx = buftls->bt_ctx; 154 int res = 0; 155 short what = EVBUFFER_WRITE; 156 157 if (event == EV_TIMEOUT) { 158 what |= EVBUFFER_TIMEOUT; 159 goto error; 160 } 161 162 if (EVBUFFER_LENGTH(bufev->output) != 0) { 163 res = evtls_write(bufev->output, fd, ctx); 164 switch (res) { 165 case TLS_WANT_POLLIN: 166 event_set(&bufev->ev_write, fd, EV_READ, 167 buffertls_writecb, buftls); 168 goto reschedule; 169 case TLS_WANT_POLLOUT: 170 event_set(&bufev->ev_write, fd, EV_WRITE, 171 buffertls_writecb, buftls); 172 goto reschedule; 173 case -1: 174 if (errno == EAGAIN || errno == EINTR || 175 errno == EINPROGRESS) 176 goto reschedule; 177 /* error case */ 178 what |= EVBUFFER_ERROR; 179 break; 180 case 0: 181 /* eof case */ 182 what |= EVBUFFER_EOF; 183 break; 184 } 185 if (res <= 0) 186 goto error; 187 } 188 189 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls); 190 if (EVBUFFER_LENGTH(bufev->output) != 0) 191 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 192 193 /* 194 * Invoke the user callback if our buffer is drained or below the 195 * low watermark. 196 */ 197 if (bufev->writecb != NULL && 198 EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low) 199 (*bufev->writecb)(bufev, bufev->cbarg); 200 201 return; 202 203 reschedule: 204 if (EVBUFFER_LENGTH(bufev->output) != 0) 205 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 206 return; 207 208 error: 209 (*bufev->errorcb)(bufev, what, bufev->cbarg); 210 } 211 212 static void 213 buffertls_handshakecb(int fd, short event, void *arg) 214 { 215 struct buffertls *buftls = arg; 216 struct bufferevent *bufev = buftls->bt_bufev; 217 struct tls *ctx = buftls->bt_ctx; 218 int res = 0; 219 short what = EVBUFFER_HANDSHAKE; 220 221 if (event == EV_TIMEOUT) { 222 what |= EVBUFFER_TIMEOUT; 223 goto error; 224 } 225 226 res = tls_handshake(ctx); 227 switch (res) { 228 case TLS_WANT_POLLIN: 229 event_set(&bufev->ev_write, fd, EV_READ, 230 buffertls_handshakecb, buftls); 231 goto reschedule; 232 case TLS_WANT_POLLOUT: 233 event_set(&bufev->ev_write, fd, EV_WRITE, 234 buffertls_handshakecb, buftls); 235 goto reschedule; 236 case -1: 237 if (errno == EAGAIN || errno == EINTR || 238 errno == EINPROGRESS) 239 goto reschedule; 240 /* error case */ 241 what |= EVBUFFER_ERROR; 242 break; 243 } 244 if (res < 0) 245 goto error; 246 247 /* 248 * There might be data available in the tls layer. Try 249 * an read operation and setup the callbacks. Call the read 250 * callback after enabling the write callback to give the 251 * read error handler a chance to disable the write event. 252 */ 253 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls); 254 if (EVBUFFER_LENGTH(bufev->output) != 0) 255 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 256 buffertls_readcb(fd, 0, buftls); 257 258 return; 259 260 reschedule: 261 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 262 return; 263 264 error: 265 (*bufev->errorcb)(bufev, what, bufev->cbarg); 266 } 267 268 void 269 buffertls_set(struct buffertls *buftls, struct bufferevent *bufev, 270 struct tls *ctx, int fd) 271 { 272 bufferevent_setfd(bufev, fd); 273 event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls); 274 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls); 275 buftls->bt_bufev = bufev; 276 buftls->bt_ctx = ctx; 277 } 278 279 void 280 buffertls_connect(struct buffertls *buftls, int fd) 281 { 282 struct bufferevent *bufev = buftls->bt_bufev; 283 284 event_del(&bufev->ev_read); 285 event_del(&bufev->ev_write); 286 287 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_handshakecb, 288 buftls); 289 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 290 } 291 292 /* 293 * Reads data from a file descriptor into a buffer. 294 */ 295 296 #define EVBUFFER_MAX_READ 4096 297 298 int 299 evtls_read(struct evbuffer *buf, int fd, int howmuch, struct tls *ctx) 300 { 301 u_char *p; 302 size_t oldoff = buf->off; 303 int n = EVBUFFER_MAX_READ; 304 305 if (ioctl(fd, FIONREAD, &n) == -1 || n <= 0) { 306 n = EVBUFFER_MAX_READ; 307 } else if (n > EVBUFFER_MAX_READ && n > howmuch) { 308 /* 309 * It's possible that a lot of data is available for 310 * reading. We do not want to exhaust resources 311 * before the reader has a chance to do something 312 * about it. If the reader does not tell us how much 313 * data we should read, we artifically limit it. 314 */ 315 if ((size_t)n > buf->totallen << 2) 316 n = buf->totallen << 2; 317 if (n < EVBUFFER_MAX_READ) 318 n = EVBUFFER_MAX_READ; 319 } 320 if (howmuch < 0 || howmuch > n) 321 howmuch = n; 322 323 /* If we don't have FIONREAD, we might waste some space here */ 324 if (evbuffer_expand(buf, howmuch) == -1) 325 return (-1); 326 327 /* We can append new data at this point */ 328 p = buf->buffer + buf->off; 329 330 n = tls_read(ctx, p, howmuch); 331 if (n <= 0) 332 return (n); 333 334 buf->off += n; 335 336 /* Tell someone about changes in this buffer */ 337 if (buf->off != oldoff && buf->cb != NULL) 338 (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); 339 340 return (n); 341 } 342 343 int 344 evtls_write(struct evbuffer *buffer, int fd, struct tls *ctx) 345 { 346 int n; 347 348 n = tls_write(ctx, buffer->buffer, buffer->off); 349 if (n <= 0) 350 return (n); 351 evbuffer_drain(buffer, n); 352 353 return (n); 354 } 355