1 /* $OpenBSD: evbuffer_tls.c,v 1.4 2015/07/06 16:12:16 millert 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_READ_AGAIN: 99 event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, 100 buftls); 101 goto reschedule; 102 case TLS_WRITE_AGAIN: 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_READ_AGAIN: 166 event_set(&bufev->ev_write, fd, EV_READ, 167 buffertls_writecb, buftls); 168 goto reschedule; 169 case TLS_WRITE_AGAIN: 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 buftls->bt_flags &= ~BT_WRITE_AGAIN; 189 190 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls); 191 if (EVBUFFER_LENGTH(bufev->output) != 0) 192 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 193 194 /* 195 * Invoke the user callback if our buffer is drained or below the 196 * low watermark. 197 */ 198 if (bufev->writecb != NULL && 199 EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low) 200 (*bufev->writecb)(bufev, bufev->cbarg); 201 202 return; 203 204 reschedule: 205 buftls->bt_flags |= BT_WRITE_AGAIN; 206 if (EVBUFFER_LENGTH(bufev->output) != 0) 207 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 208 return; 209 210 error: 211 (*bufev->errorcb)(bufev, what, bufev->cbarg); 212 } 213 214 static void 215 buffertls_connectcb(int fd, short event, void *arg) 216 { 217 struct buffertls *buftls = arg; 218 struct bufferevent *bufev = buftls->bt_bufev; 219 struct tls *ctx = buftls->bt_ctx; 220 const char *hostname = buftls->bt_hostname; 221 int res = 0; 222 short what = EVBUFFER_CONNECT; 223 224 if (event == EV_TIMEOUT) { 225 what |= EVBUFFER_TIMEOUT; 226 goto error; 227 } 228 229 res = tls_connect_socket(ctx, fd, hostname); 230 switch (res) { 231 case TLS_READ_AGAIN: 232 event_set(&bufev->ev_write, fd, EV_READ, 233 buffertls_connectcb, buftls); 234 goto reschedule; 235 case TLS_WRITE_AGAIN: 236 event_set(&bufev->ev_write, fd, EV_WRITE, 237 buffertls_connectcb, buftls); 238 goto reschedule; 239 case -1: 240 if (errno == EAGAIN || errno == EINTR || 241 errno == EINPROGRESS) 242 goto reschedule; 243 /* error case */ 244 what |= EVBUFFER_ERROR; 245 break; 246 } 247 if (res < 0) 248 goto error; 249 250 /* 251 * There might be data available in the tls layer. Try 252 * an read operation and setup the callbacks. Call the read 253 * callback after enabling the write callback to give the 254 * read error handler a chance to disable the write event. 255 */ 256 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls); 257 if (EVBUFFER_LENGTH(bufev->output) != 0) 258 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 259 buffertls_readcb(fd, 0, buftls); 260 261 return; 262 263 reschedule: 264 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 265 return; 266 267 error: 268 (*bufev->errorcb)(bufev, what, bufev->cbarg); 269 } 270 271 void 272 buffertls_set(struct buffertls *buftls, struct bufferevent *bufev, 273 struct tls *ctx, int fd) 274 { 275 bufferevent_setfd(bufev, fd); 276 event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls); 277 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls); 278 buftls->bt_bufev = bufev; 279 buftls->bt_ctx = ctx; 280 buftls->bt_flags = 0; 281 } 282 283 void 284 buffertls_connect(struct buffertls *buftls, int fd, const char *hostname) 285 { 286 struct bufferevent *bufev = buftls->bt_bufev; 287 288 event_del(&bufev->ev_read); 289 event_del(&bufev->ev_write); 290 291 buftls->bt_hostname = hostname; 292 event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_connectcb, buftls); 293 bufferevent_add(&bufev->ev_write, bufev->timeout_write); 294 } 295 296 /* 297 * Reads data from a file descriptor into a buffer. 298 */ 299 300 #define EVBUFFER_MAX_READ 4096 301 302 int 303 evtls_read(struct evbuffer *buf, int fd, int howmuch, struct tls *ctx) 304 { 305 u_char *p; 306 size_t len, oldoff = buf->off; 307 int n = EVBUFFER_MAX_READ; 308 309 if (ioctl(fd, FIONREAD, &n) == -1 || n <= 0) { 310 n = EVBUFFER_MAX_READ; 311 } else if (n > EVBUFFER_MAX_READ && n > howmuch) { 312 /* 313 * It's possible that a lot of data is available for 314 * reading. We do not want to exhaust resources 315 * before the reader has a chance to do something 316 * about it. If the reader does not tell us how much 317 * data we should read, we artifically limit it. 318 */ 319 if ((size_t)n > buf->totallen << 2) 320 n = buf->totallen << 2; 321 if (n < EVBUFFER_MAX_READ) 322 n = EVBUFFER_MAX_READ; 323 } 324 if (howmuch < 0 || howmuch > n) 325 howmuch = n; 326 327 /* If we don't have FIONREAD, we might waste some space here */ 328 if (evbuffer_expand(buf, howmuch) == -1) 329 return (-1); 330 331 /* We can append new data at this point */ 332 p = buf->buffer + buf->off; 333 334 n = tls_read(ctx, p, howmuch, &len); 335 if (n < 0 || len == 0) 336 return (n); 337 338 buf->off += len; 339 340 /* Tell someone about changes in this buffer */ 341 if (buf->off != oldoff && buf->cb != NULL) 342 (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); 343 344 return (len); 345 } 346 347 int 348 evtls_write(struct evbuffer *buffer, int fd, struct tls *ctx) 349 { 350 size_t len; 351 int n; 352 353 n = tls_write(ctx, buffer->buffer, buffer->off, &len); 354 if (n < 0 || len == 0) 355 return (n); 356 357 evbuffer_drain(buffer, len); 358 359 return (len); 360 } 361