@@ -111,6 +111,9 @@ struct wolfssl_stream_impl_
111111 };
112112 op_buffers* current_op_ = nullptr ;
113113
114+ // Renegotiation can cause both TLS read/write to access the socket
115+ capy::async_mutex io_mutex_;
116+
114117 // --------------------------------------------------------------------------
115118
116119 explicit
@@ -202,6 +205,22 @@ struct wolfssl_stream_impl_
202205 return static_cast <int >(to_copy);
203206 }
204207
208+ // --------------------------------------------------------------------------
209+
210+ capy::task<io_result<std::size_t >>
211+ do_underlying_read (capy::mutable_buffer buf)
212+ {
213+ auto guard = co_await io_mutex_.scoped_lock ();
214+ co_return co_await s_.read_some (buf);
215+ }
216+
217+ capy::task<io_result<std::size_t >>
218+ do_underlying_write (capy::mutable_buffer buf)
219+ {
220+ auto guard = co_await io_mutex_.scoped_lock ();
221+ co_return co_await s_.write_some (buf);
222+ }
223+
205224 // --------------------------------------------------------------------------
206225 // Inner coroutines for TLS read/write operations
207226 // --------------------------------------------------------------------------
@@ -262,20 +281,19 @@ struct wolfssl_stream_impl_
262281
263282 if (err == WOLFSSL_ERROR_WANT_READ)
264283 {
265- // Need to read from underlying stream
266284 if (read_in_pos_ == read_in_len_) { read_in_pos_ = 0 ; read_in_len_ = 0 ; }
267285 capy::mutable_buffer buf (read_in_buf_.data () + read_in_len_, read_in_buf_.size () - read_in_len_);
268- auto [rec, rn] = co_await s_. read_some (buf);
286+ auto [rec, rn] = co_await do_underlying_read (buf);
269287 if (rec) { ec = rec; goto done; }
270288 read_in_len_ += rn;
271289 }
272290 else if (err == WOLFSSL_ERROR_WANT_WRITE)
273291 {
274- // Need to flush output (can happen during renegotiation)
292+ // Renegotiation
275293 while (read_out_len_ > 0 )
276294 {
277295 capy::mutable_buffer buf (read_out_buf_.data (), read_out_len_);
278- auto [wec, wn] = co_await s_. write_some (buf);
296+ auto [wec, wn] = co_await do_underlying_write (buf);
279297 if (wec) { ec = wec; goto done; }
280298 if (wn < read_out_len_)
281299 std::memmove (read_out_buf_.data (), read_out_buf_.data () + wn, read_out_len_ - wn);
@@ -365,7 +383,7 @@ struct wolfssl_stream_impl_
365383 while (write_out_len_ > 0 )
366384 {
367385 capy::mutable_buffer buf (write_out_buf_.data (), write_out_len_);
368- auto [wec, wn] = co_await s_. write_some (buf);
386+ auto [wec, wn] = co_await do_underlying_write (buf);
369387 if (wec) { ec = wec; goto done; }
370388 if (wn < write_out_len_)
371389 std::memmove (write_out_buf_.data (), write_out_buf_.data () + wn, write_out_len_ - wn);
@@ -380,11 +398,10 @@ struct wolfssl_stream_impl_
380398
381399 if (err == WOLFSSL_ERROR_WANT_WRITE)
382400 {
383- // Need to flush output buffer
384401 while (write_out_len_ > 0 )
385402 {
386403 capy::mutable_buffer buf (write_out_buf_.data (), write_out_len_);
387- auto [wec, wn] = co_await s_. write_some (buf);
404+ auto [wec, wn] = co_await do_underlying_write (buf);
388405 if (wec) { ec = wec; goto done; }
389406 if (wn < write_out_len_)
390407 std::memmove (write_out_buf_.data (), write_out_buf_.data () + wn, write_out_len_ - wn);
@@ -393,10 +410,10 @@ struct wolfssl_stream_impl_
393410 }
394411 else if (err == WOLFSSL_ERROR_WANT_READ)
395412 {
396- // Need to read (can happen during renegotiation)
413+ // Renegotiation
397414 if (write_in_pos_ == write_in_len_) { write_in_pos_ = 0 ; write_in_len_ = 0 ; }
398415 capy::mutable_buffer buf (write_in_buf_.data () + write_in_len_, write_in_buf_.size () - write_in_len_);
399- auto [rec, rn] = co_await s_. read_some (buf);
416+ auto [rec, rn] = co_await do_underlying_read (buf);
400417 if (rec) { ec = rec; goto done; }
401418 write_in_len_ += rn;
402419 }
@@ -466,7 +483,7 @@ struct wolfssl_stream_impl_
466483 while (read_out_len_ > 0 )
467484 {
468485 capy::mutable_buffer buf (read_out_buf_.data (), read_out_len_);
469- auto [wec, wn] = co_await s_. write_some (buf);
486+ auto [wec, wn] = co_await do_underlying_write (buf);
470487 if (wec)
471488 {
472489 ec = wec;
@@ -484,12 +501,11 @@ struct wolfssl_stream_impl_
484501
485502 if (err == WOLFSSL_ERROR_WANT_READ)
486503 {
487- // Flush any pending output BEFORE reading
488- // (e.g., ClientHello must be sent before we can receive ServerHello)
504+ // Must flush (e.g. ClientHello) before reading ServerHello
489505 while (read_out_len_ > 0 )
490506 {
491507 capy::mutable_buffer buf (read_out_buf_.data (), read_out_len_);
492- auto [wec, wn] = co_await s_. write_some (buf);
508+ auto [wec, wn] = co_await do_underlying_write (buf);
493509 if (wec)
494510 {
495511 ec = wec;
@@ -500,7 +516,6 @@ struct wolfssl_stream_impl_
500516 read_out_len_ -= wn;
501517 }
502518
503- // Need to read from underlying stream
504519 if (read_in_pos_ == read_in_len_)
505520 {
506521 read_in_pos_ = 0 ;
@@ -509,7 +524,7 @@ struct wolfssl_stream_impl_
509524 capy::mutable_buffer buf (
510525 read_in_buf_.data () + read_in_len_,
511526 read_in_buf_.size () - read_in_len_);
512- auto [rec, rn] = co_await s_. read_some (buf);
527+ auto [rec, rn] = co_await do_underlying_read (buf);
513528 if (rec)
514529 {
515530 ec = rec;
@@ -519,11 +534,10 @@ struct wolfssl_stream_impl_
519534 }
520535 else if (err == WOLFSSL_ERROR_WANT_WRITE)
521536 {
522- // Need to flush output buffer
523537 while (read_out_len_ > 0 )
524538 {
525539 capy::mutable_buffer buf (read_out_buf_.data (), read_out_len_);
526- auto [wec, wn] = co_await s_. write_some (buf);
540+ auto [wec, wn] = co_await do_underlying_write (buf);
527541 if (wec)
528542 {
529543 ec = wec;
0 commit comments