diff --git a/mongoose.c b/mongoose.c index c0c25f19..e8e988e1 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5383,6 +5383,7 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) { if (c->is_tls && (c->rtls.len > 0 || mg_tls_pending(c) > 0)) handle_tls_recv(c); if (can_write(c)) write_conn(c); + if (!c->is_listening && c->is_tls && !c->is_tls_hs && c->send.len == 0) mg_tls_flush(c); if (c->is_draining && c->send.len == 0 && s->ttype != MIP_TTYPE_FIN) init_closure(c); // For non-TLS, close immediately upon completing the 3-way closure @@ -9341,11 +9342,10 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) { if (c->is_readable) accept_conn(mgr, c); } else if (c->is_connecting) { if (c->is_readable || c->is_writable) connect_conn(c); - //} else if (c->is_tls_hs) { - // if ((c->is_readable || c->is_writable)) mg_tls_handshake(c); } else { if (c->is_readable) read_conn(c); if (c->is_writable) write_conn(c); + if (c->is_tls && !c->is_tls_hs && c->send.len == 0) mg_tls_flush(c); } if (c->is_draining && c->send.len == 0) c->is_closing = 1; @@ -12382,6 +12382,7 @@ void mg_tls_handshake(struct mg_connection *c) { struct tls_data *tls = (struct tls_data *) c->tls; long n; if (c->is_client) { + // will clear is_hs when sending last chunk mg_tls_client_handshake(c); } else { mg_tls_server_handshake(c); @@ -12389,7 +12390,8 @@ void mg_tls_handshake(struct mg_connection *c) { while (tls->send.len > 0 && (n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) { mg_iobuf_del(&tls->send, 0, (size_t) n); - } + } // if last chunk fails to be sent, it will be sent with first app data, + // otherwise, it needs to be flushed } static int mg_parse_pem(const struct mg_str pem, const struct mg_str label, @@ -12523,7 +12525,7 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) { while (tls->send.len > 0 && (n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) { mg_iobuf_del(&tls->send, 0, (size_t) n); - } + } // if last chunk fails to be sent, it needs to be flushed c->is_tls_throttled = (tls->send.len > 0 && n == MG_IO_WAIT); MG_VERBOSE(("%lu %ld %ld %ld %c %c", c->id, (long) len, (long) tls->send.len, n, was_throttled ? 'T' : 't', c->is_tls_throttled ? 'T' : 't')); @@ -12565,6 +12567,15 @@ size_t mg_tls_pending(struct mg_connection *c) { return tls != NULL ? tls->recv_len : 0; } +void mg_tls_flush(struct mg_connection *c) { + struct tls_data *tls = (struct tls_data *) c->tls; + long n; + while (tls->send.len > 0 && + (n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) { + mg_iobuf_del(&tls->send, 0, (size_t) n); + } +} + void mg_tls_ctx_init(struct mg_mgr *mgr) { (void) mgr; } @@ -13947,6 +13958,9 @@ size_t mg_tls_pending(struct mg_connection *c) { (void) c; return 0; } +void mg_tls_flush(struct mg_connection *c) { + (void) c; +} void mg_tls_ctx_init(struct mg_mgr *mgr) { (void) mgr; } @@ -14164,11 +14178,18 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) { tls->throttled_buf = (unsigned char *)buf; // MbedTLS code actually ignores tls->throttled_len = len; // these, but let's play API rules return (long) len; // already encripted that when throttled - } + } // if last chunk fails to be sent, it needs to be flushed if (n <= 0) return MG_IO_ERR; return n; } +void mg_tls_flush(struct mg_connection *c) { + if (c->is_tls_throttled) { + long n = mbedtls_ssl_write(&tls->ssl, tls->throttled_buf, tls->throttled_len); + c->is_tls_throttled = (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE); + } +} + void mg_tls_ctx_init(struct mg_mgr *mgr) { struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) calloc(1, sizeof(*ctx)); if (ctx == NULL) { @@ -14474,6 +14495,10 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) { return n; } +void mg_tls_flush(struct mg_connection *c) { + (void) c; +} + void mg_tls_ctx_init(struct mg_mgr *mgr) { (void) mgr; } diff --git a/mongoose.h b/mongoose.h index fd857e3c..28d69528 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2424,6 +2424,7 @@ void mg_tls_free(struct mg_connection *); long mg_tls_send(struct mg_connection *, const void *buf, size_t len); long mg_tls_recv(struct mg_connection *, void *buf, size_t len); size_t mg_tls_pending(struct mg_connection *); +void mg_tls_flush(struct mg_connection *); void mg_tls_handshake(struct mg_connection *); // Private diff --git a/src/net_builtin.c b/src/net_builtin.c index c027e57e..4ec0d0bb 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -1218,6 +1218,7 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) { if (c->is_tls && (c->rtls.len > 0 || mg_tls_pending(c) > 0)) handle_tls_recv(c); if (can_write(c)) write_conn(c); + if (!c->is_listening && c->is_tls && !c->is_tls_hs && c->send.len == 0) mg_tls_flush(c); if (c->is_draining && c->send.len == 0 && s->ttype != MIP_TTYPE_FIN) init_closure(c); // For non-TLS, close immediately upon completing the 3-way closure diff --git a/src/sock.c b/src/sock.c index 64147555..47859ea3 100644 --- a/src/sock.c +++ b/src/sock.c @@ -734,11 +734,10 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) { if (c->is_readable) accept_conn(mgr, c); } else if (c->is_connecting) { if (c->is_readable || c->is_writable) connect_conn(c); - //} else if (c->is_tls_hs) { - // if ((c->is_readable || c->is_writable)) mg_tls_handshake(c); } else { if (c->is_readable) read_conn(c); if (c->is_writable) write_conn(c); + if (c->is_tls && !c->is_tls_hs && c->send.len == 0) mg_tls_flush(c); } if (c->is_draining && c->send.len == 0) c->is_closing = 1; diff --git a/src/tls.h b/src/tls.h index 95376c1a..188fbf46 100644 --- a/src/tls.h +++ b/src/tls.h @@ -28,6 +28,7 @@ void mg_tls_free(struct mg_connection *); long mg_tls_send(struct mg_connection *, const void *buf, size_t len); long mg_tls_recv(struct mg_connection *, void *buf, size_t len); size_t mg_tls_pending(struct mg_connection *); +void mg_tls_flush(struct mg_connection *); void mg_tls_handshake(struct mg_connection *); // Private diff --git a/src/tls_builtin.c b/src/tls_builtin.c index e983687d..bb9035ba 100644 --- a/src/tls_builtin.c +++ b/src/tls_builtin.c @@ -1557,6 +1557,7 @@ void mg_tls_handshake(struct mg_connection *c) { struct tls_data *tls = (struct tls_data *) c->tls; long n; if (c->is_client) { + // will clear is_hs when sending last chunk mg_tls_client_handshake(c); } else { mg_tls_server_handshake(c); @@ -1564,7 +1565,8 @@ void mg_tls_handshake(struct mg_connection *c) { while (tls->send.len > 0 && (n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) { mg_iobuf_del(&tls->send, 0, (size_t) n); - } + } // if last chunk fails to be sent, it will be sent with first app data, + // otherwise, it needs to be flushed } static int mg_parse_pem(const struct mg_str pem, const struct mg_str label, @@ -1698,7 +1700,7 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) { while (tls->send.len > 0 && (n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) { mg_iobuf_del(&tls->send, 0, (size_t) n); - } + } // if last chunk fails to be sent, it needs to be flushed c->is_tls_throttled = (tls->send.len > 0 && n == MG_IO_WAIT); MG_VERBOSE(("%lu %ld %ld %ld %c %c", c->id, (long) len, (long) tls->send.len, n, was_throttled ? 'T' : 't', c->is_tls_throttled ? 'T' : 't')); @@ -1740,6 +1742,15 @@ size_t mg_tls_pending(struct mg_connection *c) { return tls != NULL ? tls->recv_len : 0; } +void mg_tls_flush(struct mg_connection *c) { + struct tls_data *tls = (struct tls_data *) c->tls; + long n; + while (tls->send.len > 0 && + (n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) { + mg_iobuf_del(&tls->send, 0, (size_t) n); + } +} + void mg_tls_ctx_init(struct mg_mgr *mgr) { (void) mgr; } diff --git a/src/tls_dummy.c b/src/tls_dummy.c index 2c8dedcc..d68c3f52 100644 --- a/src/tls_dummy.c +++ b/src/tls_dummy.c @@ -21,6 +21,9 @@ size_t mg_tls_pending(struct mg_connection *c) { (void) c; return 0; } +void mg_tls_flush(struct mg_connection *c) { + (void) c; +} void mg_tls_ctx_init(struct mg_mgr *mgr) { (void) mgr; } diff --git a/src/tls_mbed.c b/src/tls_mbed.c index 9b249df1..b1ef337f 100644 --- a/src/tls_mbed.c +++ b/src/tls_mbed.c @@ -204,11 +204,18 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) { tls->throttled_buf = (unsigned char *)buf; // MbedTLS code actually ignores tls->throttled_len = len; // these, but let's play API rules return (long) len; // already encripted that when throttled - } + } // if last chunk fails to be sent, it needs to be flushed if (n <= 0) return MG_IO_ERR; return n; } +void mg_tls_flush(struct mg_connection *c) { + if (c->is_tls_throttled) { + long n = mbedtls_ssl_write(&tls->ssl, tls->throttled_buf, tls->throttled_len); + c->is_tls_throttled = (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE); + } +} + void mg_tls_ctx_init(struct mg_mgr *mgr) { struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) calloc(1, sizeof(*ctx)); if (ctx == NULL) { diff --git a/src/tls_openssl.c b/src/tls_openssl.c index d2382543..5af22e33 100644 --- a/src/tls_openssl.c +++ b/src/tls_openssl.c @@ -270,6 +270,10 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) { return n; } +void mg_tls_flush(struct mg_connection *c) { + (void) c; +} + void mg_tls_ctx_init(struct mg_mgr *mgr) { (void) mgr; }