2 * nghttp2 - HTTP/2 C Library
4 * Copyright (c) 2015 Tatsuhiro Tsujikawa
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 #include "shrpx_connection.h"
29 #endif // HAVE_UNISTD_H
33 #include <openssl/err.h>
37 using namespace nghttp2;
40 Connection::Connection(struct ev_loop *loop, int fd, SSL *ssl,
41 ev_tstamp write_timeout, ev_tstamp read_timeout,
42 size_t write_rate, size_t write_burst, size_t read_rate,
43 size_t read_burst, IOCb writecb, IOCb readcb,
44 TimerCb timeoutcb, void *data)
45 : tls{ssl}, wlimit(loop, &wev, write_rate, write_burst),
46 rlimit(loop, &rev, read_rate, read_burst, ssl), writecb(writecb),
47 readcb(readcb), timeoutcb(timeoutcb), loop(loop), data(data), fd(fd) {
49 ev_io_init(&wev, writecb, fd, EV_WRITE);
50 ev_io_init(&rev, readcb, fd, EV_READ);
55 ev_timer_init(&wt, timeoutcb, 0., write_timeout);
56 ev_timer_init(&rt, timeoutcb, 0., read_timeout);
61 // set 0. to double field explicitly just in case
62 tls.last_write_time = 0.;
65 Connection::~Connection() { disconnect(); }
67 void Connection::disconnect() {
68 ev_timer_stop(loop, &rt);
69 ev_timer_stop(loop, &wt);
75 SSL_set_app_data(tls.ssl, nullptr);
76 SSL_set_shutdown(tls.ssl, SSL_RECEIVED_SHUTDOWN);
78 SSL_shutdown(tls.ssl);
84 shutdown(fd, SHUT_WR);
90 int Connection::tls_handshake() {
91 auto rv = SSL_do_handshake(tls.ssl);
94 return SHRPX_ERR_NETWORK;
98 auto err = SSL_get_error(tls.ssl, rv);
100 case SSL_ERROR_WANT_READ:
102 ev_timer_stop(loop, &wt);
103 return SHRPX_ERR_INPROGRESS;
104 case SSL_ERROR_WANT_WRITE:
106 ev_timer_again(loop, &wt);
107 return SHRPX_ERR_INPROGRESS;
109 return SHRPX_ERR_NETWORK;
114 ev_timer_stop(loop, &wt);
116 tls.initial_handshake_done = true;
118 if (LOG_ENABLED(INFO)) {
119 LOG(INFO) << "SSL/TLS handshake completed";
120 if (SSL_session_reused(tls.ssl)) {
121 LOG(INFO) << "SSL/TLS session reused";
129 const size_t SHRPX_SMALL_WRITE_LIMIT = 1300;
130 const size_t SHRPX_WARMUP_THRESHOLD = 1 << 20;
133 size_t Connection::get_tls_write_limit() {
134 auto t = ev_now(loop);
136 if (t - tls.last_write_time > 1.) {
137 // Time out, use small record size
138 tls.warmup_writelen = 0;
139 return SHRPX_SMALL_WRITE_LIMIT;
142 if (tls.warmup_writelen >= SHRPX_WARMUP_THRESHOLD) {
143 return std::numeric_limits<ssize_t>::max();
146 return SHRPX_SMALL_WRITE_LIMIT;
149 void Connection::update_tls_warmup_writelen(size_t n) {
150 if (tls.warmup_writelen < SHRPX_WARMUP_THRESHOLD) {
151 tls.warmup_writelen += n;
155 ssize_t Connection::write_tls(const void *data, size_t len) {
156 // SSL_write requires the same arguments (buf pointer and its
157 // length) on SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE.
158 // get_write_limit() may return smaller length than previously
159 // passed to SSL_write, which violates OpenSSL assumption. To avoid
160 // this, we keep last legnth passed to SSL_write to
161 // tls.last_writelen if SSL_write indicated I/O blocking.
162 if (tls.last_writelen == 0) {
163 len = std::min(len, wlimit.avail());
164 len = std::min(len, get_tls_write_limit());
169 len = tls.last_writelen;
170 tls.last_writelen = 0;
173 auto rv = SSL_write(tls.ssl, data, len);
176 return SHRPX_ERR_NETWORK;
179 tls.last_write_time = ev_now(loop);
182 auto err = SSL_get_error(tls.ssl, rv);
184 case SSL_ERROR_WANT_READ:
185 if (LOG_ENABLED(INFO)) {
186 LOG(INFO) << "Close connection due to TLS renegotiation";
188 return SHRPX_ERR_NETWORK;
189 case SSL_ERROR_WANT_WRITE:
190 tls.last_writelen = len;
192 ev_timer_again(loop, &wt);
195 if (LOG_ENABLED(INFO)) {
196 LOG(INFO) << "SSL_write: SSL_get_error returned " << err;
198 return SHRPX_ERR_NETWORK;
204 update_tls_warmup_writelen(rv);
209 ssize_t Connection::read_tls(void *data, size_t len) {
210 // SSL_read requires the same arguments (buf pointer and its
211 // length) on SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE.
212 // rlimit_.avail() or rlimit_.avail() may return different length
213 // than the length previously passed to SSL_read, which violates
214 // OpenSSL assumption. To avoid this, we keep last legnth passed
215 // to SSL_read to tls_last_readlen_ if SSL_read indicated I/O
217 if (tls.last_readlen == 0) {
218 len = std::min(len, rlimit.avail());
223 len = tls.last_readlen;
224 tls.last_readlen = 0;
227 auto rv = SSL_read(tls.ssl, data, len);
230 auto err = SSL_get_error(tls.ssl, rv);
232 case SSL_ERROR_WANT_READ:
233 tls.last_readlen = len;
235 case SSL_ERROR_WANT_WRITE:
236 if (LOG_ENABLED(INFO)) {
237 LOG(INFO) << "Close connection due to TLS renegotiation";
239 return SHRPX_ERR_NETWORK;
240 case SSL_ERROR_ZERO_RETURN:
241 return SHRPX_ERR_EOF;
243 if (LOG_ENABLED(INFO)) {
244 LOG(INFO) << "SSL_read: SSL_get_error returned " << err;
246 return SHRPX_ERR_NETWORK;
255 ssize_t Connection::write_clear(const void *data, size_t len) {
256 len = std::min(len, wlimit.avail());
262 while ((nwrite = write(fd, data, len)) == -1 && errno == EINTR)
265 if (errno == EAGAIN || errno == EWOULDBLOCK) {
267 ev_timer_again(loop, &wt);
270 return SHRPX_ERR_NETWORK;
273 wlimit.drain(nwrite);
278 ssize_t Connection::writev_clear(struct iovec *iov, int iovcnt) {
279 iovcnt = limit_iovec(iov, iovcnt, wlimit.avail());
285 while ((nwrite = writev(fd, iov, iovcnt)) == -1 && errno == EINTR)
288 if (errno == EAGAIN || errno == EWOULDBLOCK) {
290 ev_timer_again(loop, &wt);
293 return SHRPX_ERR_NETWORK;
296 wlimit.drain(nwrite);
301 ssize_t Connection::read_clear(void *data, size_t len) {
302 len = std::min(len, rlimit.avail());
308 while ((nread = read(fd, data, len)) == -1 && errno == EINTR)
311 if (errno == EAGAIN || errno == EWOULDBLOCK) {
314 return SHRPX_ERR_NETWORK;
318 return SHRPX_ERR_EOF;
326 void Connection::handle_tls_pending_read() {
327 if (!ev_is_active(&rev)) {
330 rlimit.handle_tls_pending_read();