MCPcopy Index your code
hub / github.com/RustPython/RustPython / handle_handshake_complete

Function handle_handshake_complete

crates/stdlib/src/ssl/compat.rs:1340–1410  ·  view source on GitHub ↗

Handle handshake completion for server-side TLS 1.3 Tries to send NewSessionTicket in non-blocking mode to avoid deadlocks. Returns true if handshake is complete and we should exit.

(
    conn: &mut TlsConnection,
    socket: &PySSLSocket,
    _is_server: bool,
    vm: &VirtualMachine,
)

Source from the content-addressed store, hash-verified

1338/// Tries to send NewSessionTicket in non-blocking mode to avoid deadlocks.
1339/// Returns true if handshake is complete and we should exit.
1340fn handle_handshake_complete(
1341 conn: &mut TlsConnection,
1342 socket: &PySSLSocket,
1343 _is_server: bool,
1344 vm: &VirtualMachine,
1345) -> SslResult<bool> {
1346 if conn.is_handshaking() {
1347 return Ok(false); // Not complete yet
1348 }
1349
1350 // Handshake is complete!
1351 //
1352 // Different behavior for BIO mode vs socket mode:
1353 //
1354 // BIO mode (CPython-compatible):
1355 // - Python code calls outgoing.read() to get pending data
1356 // - We just return here and let Python handle the data
1357 //
1358 // Socket mode (rustls-specific):
1359 // - OpenSSL automatically writes to socket in SSL_do_handshake()
1360 // - We must explicitly call write_tls() to send pending data
1361 // - Without this, client hangs waiting for server's NewSessionTicket
1362
1363 if socket.is_bio_mode() {
1364 // BIO mode: Write pending data to outgoing BIO (one-time drain)
1365 // Python's ssl_io_loop will read from outgoing BIO
1366 if conn.wants_write() {
1367 // Call write_tls ONCE to drain pending data
1368 // Do NOT loop on wants_write() - avoid infinite loop/deadlock
1369 let tls_data = ssl_write_tls_records(conn)?;
1370 if !tls_data.is_empty() {
1371 send_all_bytes(socket, tls_data, vm, None)?;
1372 }
1373
1374 // IMPORTANT: Don't check wants_write() again!
1375 // Python's ssl_io_loop will call do_handshake() again if needed
1376 }
1377 } else if conn.wants_write() {
1378 // Send all pending data (e.g., TLS 1.3 NewSessionTicket) to socket
1379 // Must drain ALL rustls buffer - don't break on WantWrite
1380 while conn.wants_write() {
1381 let tls_data = ssl_write_tls_records(conn)?;
1382 if tls_data.is_empty() {
1383 break;
1384 }
1385 match send_all_bytes(socket, tls_data, vm, None) {
1386 Ok(()) => {}
1387 Err(SslError::WantWrite) => {
1388 // Socket buffer full, data saved to pending_tls_output
1389 // Flush pending and continue draining rustls buffer
1390 socket
1391 .blocking_flush_all_pending(vm)
1392 .map_err(SslError::Py)?;
1393 }
1394 Err(e) => return Err(e),
1395 }
1396 }
1397 }

Callers 1

ssl_do_handshakeFunction · 0.85

Calls 8

ssl_write_tls_recordsFunction · 0.85
send_all_bytesFunction · 0.85
is_handshakingMethod · 0.80
is_bio_modeMethod · 0.80
wants_writeMethod · 0.80
ErrClass · 0.50
is_emptyMethod · 0.45

Tested by

no test coverage detected