Flush any pending TLS output data to the socket Optional deadline parameter allows respecting a read deadline during flush
(
&self,
vm: &VirtualMachine,
deadline: Option<std::time::Instant>,
)
| 2825 | /// Flush any pending TLS output data to the socket |
| 2826 | /// Optional deadline parameter allows respecting a read deadline during flush |
| 2827 | pub(crate) fn flush_pending_tls_output( |
| 2828 | &self, |
| 2829 | vm: &VirtualMachine, |
| 2830 | deadline: Option<std::time::Instant>, |
| 2831 | ) -> PyResult<()> { |
| 2832 | let mut pending = self.pending_tls_output.lock(); |
| 2833 | if pending.is_empty() { |
| 2834 | return Ok(()); |
| 2835 | } |
| 2836 | |
| 2837 | let socket_timeout = self.get_socket_timeout(vm)?; |
| 2838 | let is_non_blocking = socket_timeout.map(|t| t.is_zero()).unwrap_or(false); |
| 2839 | |
| 2840 | let mut sent_total = 0; |
| 2841 | |
| 2842 | while sent_total < pending.len() { |
| 2843 | // Calculate timeout: use deadline if provided, otherwise use socket timeout |
| 2844 | let timeout_to_use = if let Some(dl) = deadline { |
| 2845 | let now = std::time::Instant::now(); |
| 2846 | if now >= dl { |
| 2847 | // Deadline already passed |
| 2848 | *pending = pending[sent_total..].to_vec(); |
| 2849 | return Err( |
| 2850 | timeout_error_msg(vm, "The operation timed out".to_string()).upcast() |
| 2851 | ); |
| 2852 | } |
| 2853 | Some(dl - now) |
| 2854 | } else { |
| 2855 | socket_timeout |
| 2856 | }; |
| 2857 | |
| 2858 | // Use sock_select directly with calculated timeout |
| 2859 | let py_socket: PyRef<PySocket> = self.sock.clone().try_into_value(vm)?; |
| 2860 | let socket = py_socket |
| 2861 | .sock() |
| 2862 | .map_err(|e| vm.new_os_error(format!("Failed to get socket: {e}")))?; |
| 2863 | let timed_out = sock_select(&socket, SelectKind::Write, timeout_to_use) |
| 2864 | .map_err(|e| vm.new_os_error(format!("select failed: {e}")))?; |
| 2865 | |
| 2866 | if timed_out { |
| 2867 | // Keep unsent data in pending buffer |
| 2868 | *pending = pending[sent_total..].to_vec(); |
| 2869 | if is_non_blocking { |
| 2870 | return Err(create_ssl_want_write_error(vm).upcast()); |
| 2871 | } |
| 2872 | return Err( |
| 2873 | timeout_error_msg(vm, "The write operation timed out".to_string()).upcast(), |
| 2874 | ); |
| 2875 | } |
| 2876 | |
| 2877 | match self.sock_send(&pending[sent_total..], vm) { |
| 2878 | Ok(result) => { |
| 2879 | let sent: usize = result.try_to_value::<isize>(vm)?.try_into().unwrap_or(0); |
| 2880 | if sent == 0 { |
| 2881 | if is_non_blocking { |
| 2882 | // Keep unsent data in pending buffer |
| 2883 | *pending = pending[sent_total..].to_vec(); |
| 2884 | return Err(create_ssl_want_write_error(vm).upcast()); |
no test coverage detected