(
conn: &mut TlsConnection,
socket: &PySSLSocket,
is_bio: bool,
is_server: bool,
vm: &VirtualMachine,
)
| 1269 | } |
| 1270 | |
| 1271 | fn handshake_read_data( |
| 1272 | conn: &mut TlsConnection, |
| 1273 | socket: &PySSLSocket, |
| 1274 | is_bio: bool, |
| 1275 | is_server: bool, |
| 1276 | vm: &VirtualMachine, |
| 1277 | ) -> SslResult<(bool, bool)> { |
| 1278 | if !conn.wants_read() { |
| 1279 | return Ok((false, false)); |
| 1280 | } |
| 1281 | |
| 1282 | // SERVER-SPECIFIC: Check if this is the first read (for SNI callback) |
| 1283 | // Must check BEFORE reading data, so we can detect first time |
| 1284 | let is_first_sni_read = is_server && socket.is_first_sni_read(); |
| 1285 | |
| 1286 | // Wait for data in socket mode |
| 1287 | if !is_bio { |
| 1288 | let timed_out = socket |
| 1289 | .sock_wait_for_io_impl(SelectKind::Read, vm) |
| 1290 | .map_err(SslError::Py)?; |
| 1291 | |
| 1292 | if timed_out { |
| 1293 | // This should rarely happen now - only if socket itself has a timeout |
| 1294 | // and we're waiting for required handshake data |
| 1295 | return Err(SslError::Timeout("timed out".to_string())); |
| 1296 | } |
| 1297 | } |
| 1298 | |
| 1299 | let data_obj = if !is_bio { |
| 1300 | // In socket mode, read one TLS record at a time to avoid consuming |
| 1301 | // application data that may arrive alongside the final handshake |
| 1302 | // record. This matches OpenSSL's default (no read-ahead) behaviour |
| 1303 | // and keeps remaining data in the kernel buffer where select() can |
| 1304 | // detect it. |
| 1305 | recv_one_tls_record(socket, vm)? |
| 1306 | } else { |
| 1307 | match socket.sock_recv(SSL3_RT_MAX_PLAIN_LENGTH, vm) { |
| 1308 | Ok(d) => d, |
| 1309 | Err(e) => { |
| 1310 | if is_blocking_io_error(&e, vm) { |
| 1311 | return Err(SslError::WantRead); |
| 1312 | } |
| 1313 | if !conn.wants_write() && e.fast_isinstance(vm.ctx.exceptions.timeout_error) { |
| 1314 | return Ok((false, false)); |
| 1315 | } |
| 1316 | return Err(SslError::Py(e)); |
| 1317 | } |
| 1318 | } |
| 1319 | }; |
| 1320 | |
| 1321 | // SERVER-SPECIFIC: Save ClientHello on first read for potential connection recreation |
| 1322 | if is_first_sni_read { |
| 1323 | // Extract bytes from PyObjectRef |
| 1324 | use rustpython_vm::builtins::PyBytes; |
| 1325 | if let Some(bytes_obj) = data_obj.downcast_ref::<PyBytes>() { |
| 1326 | socket.save_client_hello_from_bytes(bytes_obj.as_bytes()); |
| 1327 | } |
| 1328 | } |
no test coverage detected