@@ -1010,17 +1010,35 @@ pub(super) fn is_blocking_io_error(err: &Py<PyBaseException>, vm: &VirtualMachin
10101010/// Loops until all bytes are sent. For blocking sockets, this will wait
10111011/// until all data is sent. For non-blocking sockets, returns WantWrite
10121012/// if no progress can be made.
1013- fn send_all_bytes ( socket : & PySSLSocket , buf : Vec < u8 > , vm : & VirtualMachine ) -> SslResult < ( ) > {
1014- // First, flush any previously pending TLS data
1015- // Must succeed before sending new data to maintain order
1016- socket. flush_pending_tls_output ( vm) . map_err ( SslError :: Py ) ?;
1013+ /// Optional deadline parameter allows respecting a read deadline during flush.
1014+ fn send_all_bytes (
1015+ socket : & PySSLSocket ,
1016+ buf : Vec < u8 > ,
1017+ vm : & VirtualMachine ,
1018+ deadline : Option < std:: time:: Instant > ,
1019+ ) -> SslResult < ( ) > {
1020+ // First, flush any previously pending TLS data with deadline
1021+ socket
1022+ . flush_pending_tls_output ( vm, deadline)
1023+ . map_err ( SslError :: Py ) ?;
10171024
10181025 if buf. is_empty ( ) {
10191026 return Ok ( ( ) ) ;
10201027 }
10211028
10221029 let mut sent_total = 0 ;
10231030 while sent_total < buf. len ( ) {
1031+ // Check deadline before each send attempt
1032+ if let Some ( dl) = deadline {
1033+ if std:: time:: Instant :: now ( ) >= dl {
1034+ socket
1035+ . pending_tls_output
1036+ . lock ( )
1037+ . extend_from_slice ( & buf[ sent_total..] ) ;
1038+ return Err ( SslError :: Timeout ( "The operation timed out" . to_string ( ) ) ) ;
1039+ }
1040+ }
1041+
10241042 match socket. sock_send ( & buf[ sent_total..] , vm) {
10251043 Ok ( result) => {
10261044 let sent: usize = result
@@ -1075,7 +1093,9 @@ fn handshake_write_loop(
10751093
10761094 // Flush any previously pending TLS data before generating new output
10771095 // Must succeed before sending new data to maintain order
1078- socket. flush_pending_tls_output ( vm) . map_err ( SslError :: Py ) ?;
1096+ socket
1097+ . flush_pending_tls_output ( vm, None )
1098+ . map_err ( SslError :: Py ) ?;
10791099
10801100 while conn. wants_write ( ) || force_initial_write {
10811101 if force_initial_write && !conn. wants_write ( ) {
@@ -1090,7 +1110,7 @@ fn handshake_write_loop(
10901110
10911111 if written > 0 && !buf. is_empty ( ) {
10921112 // Send all bytes to socket, handling partial sends
1093- send_all_bytes ( socket, buf, vm) ?;
1113+ send_all_bytes ( socket, buf, vm, None ) ?;
10941114 made_progress = true ;
10951115 } else if written == 0 {
10961116 // No data written but wants_write is true - should not happen normally
@@ -1209,7 +1229,7 @@ fn handle_handshake_complete(
12091229 // Do NOT loop on wants_write() - avoid infinite loop/deadlock
12101230 let tls_data = ssl_write_tls_records ( conn) ?;
12111231 if !tls_data. is_empty ( ) {
1212- send_all_bytes ( socket, tls_data, vm) ?;
1232+ send_all_bytes ( socket, tls_data, vm, None ) ?;
12131233 }
12141234
12151235 // IMPORTANT: Don't check wants_write() again!
@@ -1224,7 +1244,7 @@ fn handle_handshake_complete(
12241244 if tls_data. is_empty ( ) {
12251245 break ;
12261246 }
1227- match send_all_bytes ( socket, tls_data, vm) {
1247+ match send_all_bytes ( socket, tls_data, vm, None ) {
12281248 Ok ( ( ) ) => { }
12291249 Err ( SslError :: WantWrite ) => break ,
12301250 Err ( e) => return Err ( e) ,
@@ -1314,13 +1334,13 @@ pub(super) fn ssl_do_handshake(
13141334 if !is_bio {
13151335 conn. send_close_notify ( ) ;
13161336 // Flush any pending TLS data before sending close_notify
1317- let _ = socket. flush_pending_tls_output ( vm) ;
1337+ let _ = socket. flush_pending_tls_output ( vm, None ) ;
13181338 // Actually send the close_notify alert using send_all_bytes
13191339 // for proper partial send handling and retry logic
13201340 if let Ok ( alert_data) = ssl_write_tls_records ( conn)
13211341 && !alert_data. is_empty ( )
13221342 {
1323- let _ = send_all_bytes ( socket, alert_data, vm) ;
1343+ let _ = send_all_bytes ( socket, alert_data, vm, None ) ;
13241344 }
13251345 }
13261346
@@ -1371,7 +1391,7 @@ pub(super) fn ssl_do_handshake(
13711391 break ;
13721392 }
13731393 // Send to outgoing BIO
1374- send_all_bytes ( socket, buf[ ..n] . to_vec ( ) , vm) ?;
1394+ send_all_bytes ( socket, buf[ ..n] . to_vec ( ) , vm, None ) ?;
13751395 // Check if there's more to write
13761396 if !conn. wants_write ( ) {
13771397 break ;
@@ -1496,15 +1516,20 @@ pub(super) fn ssl_read(
14961516 }
14971517
14981518 // Flush pending TLS data before continuing
1519+ // CRITICAL: Pass deadline so flush respects read timeout
14991520 let tls_data = ssl_write_tls_records ( conn) ?;
15001521 if !tls_data. is_empty ( ) {
15011522 // Use best-effort send - don't fail READ just because WRITE couldn't complete
1502- match send_all_bytes ( socket, tls_data, vm) {
1523+ match send_all_bytes ( socket, tls_data, vm, deadline ) {
15031524 Ok ( ( ) ) => { }
15041525 Err ( SslError :: WantWrite ) => {
15051526 // Socket buffer full - acceptable during READ operation
15061527 // Pending data will be sent on next write/read call
15071528 }
1529+ Err ( SslError :: Timeout ( _) ) => {
1530+ // Timeout during flush is acceptable during READ
1531+ // Pending data stays buffered for next operation
1532+ }
15081533 Err ( e) => return Err ( e) ,
15091534 }
15101535 }
0 commit comments