@@ -35,6 +35,8 @@ struct ssl_backend_data {
3535#ifdef HAS_ALPN
3636 const char * protocols [ALPN_ENTRIES_MAX + 1 ];
3737#endif
38+ size_t send_blocked_len ;
39+ BIT (send_blocked );
3840};
3941
4042/*
@@ -310,6 +312,18 @@ static ssize_t unitytls_send(struct Curl_cfilter *cf, struct Curl_easy *data,
310312 struct ssl_connect_data * connssl = cf -> ctx ;
311313 struct ssl_backend_data * backend = connssl -> backend ;
312314
315+ /* Similar to mbedtls implementation, if unitytls_tlsctx_write was
316+ * previously blocked, it must be called with the same amount of bytes
317+ * again, or it will lose bytes , e.g. reporting all was sent but they
318+ * were not. If that happens, the other side errors and hangs up.
319+ * Remember the blocked length and use that when it is set. */
320+ if (backend -> send_blocked ) {
321+ DEBUGASSERT (backend -> send_blocked_len <= len );
322+ CURL_TRC_CF (data , cf , "unitytls_tlsctx_write(len=%zu) -> previously blocked "
323+ "on %zu bytes" , len , backend -> send_blocked_len );
324+ len = backend -> send_blocked_len ;
325+ }
326+
313327 size_t written = 0 ;
314328 unitytls_errorstate err = unitytls -> unitytls_errorstate_create ();
315329 written = unitytls -> unitytls_tlsctx_write (backend -> ctx , (const UInt8 * )mem , len , & err );
@@ -321,9 +335,15 @@ static ssize_t unitytls_send(struct Curl_cfilter *cf, struct Curl_easy *data,
321335 * curlcode = CURLE_SEND_ERROR ;
322336 failf (data , "Sending data failed with unitytls error code %i" , err .code );
323337 }
338+ if ((* curlcode == CURLE_AGAIN ) && !backend -> send_blocked ) {
339+ backend -> send_blocked = TRUE;
340+ backend -> send_blocked_len = len ;
341+ }
324342 return -1 ;
325343 }
326344
345+ CURL_TRC_CF (data , cf , "unitytls_tlsctx_write(len=%zu) -> %d" , len , err .code );
346+ backend -> send_blocked = FALSE;
327347 return written ;
328348}
329349
0 commit comments