Send TLS output data to socket, saving unsent bytes to pending buffer This prevents data loss when rustls' write_tls() drains its internal buffer but the socket cannot accept all the data immediately
(&self, buf: Vec<u8>, vm: &VirtualMachine)
| 2913 | /// This prevents data loss when rustls' write_tls() drains its internal buffer |
| 2914 | /// but the socket cannot accept all the data immediately |
| 2915 | fn send_tls_output(&self, buf: Vec<u8>, vm: &VirtualMachine) -> PyResult<()> { |
| 2916 | if buf.is_empty() { |
| 2917 | return Ok(()); |
| 2918 | } |
| 2919 | |
| 2920 | let timeout = self.get_socket_timeout(vm)?; |
| 2921 | let is_non_blocking = timeout.map(|t| t.is_zero()).unwrap_or(false); |
| 2922 | |
| 2923 | let mut sent_total = 0; |
| 2924 | while sent_total < buf.len() { |
| 2925 | let timed_out = self.sock_wait_for_io_impl(SelectKind::Write, vm)?; |
| 2926 | if timed_out { |
| 2927 | // Save unsent data to pending buffer |
| 2928 | self.pending_tls_output |
| 2929 | .lock() |
| 2930 | .extend_from_slice(&buf[sent_total..]); |
| 2931 | return Err( |
| 2932 | timeout_error_msg(vm, "The write operation timed out".to_string()).upcast(), |
| 2933 | ); |
| 2934 | } |
| 2935 | |
| 2936 | match self.sock_send(&buf[sent_total..], vm) { |
| 2937 | Ok(result) => { |
| 2938 | let sent: usize = result.try_to_value::<isize>(vm)?.try_into().unwrap_or(0); |
| 2939 | if sent == 0 { |
| 2940 | if is_non_blocking { |
| 2941 | // Save unsent data to pending buffer |
| 2942 | self.pending_tls_output |
| 2943 | .lock() |
| 2944 | .extend_from_slice(&buf[sent_total..]); |
| 2945 | return Err(create_ssl_want_write_error(vm).upcast()); |
| 2946 | } |
| 2947 | continue; |
| 2948 | } |
| 2949 | sent_total += sent; |
| 2950 | } |
| 2951 | Err(e) => { |
| 2952 | if is_blocking_io_error(&e, vm) { |
| 2953 | if is_non_blocking { |
| 2954 | // Save unsent data to pending buffer |
| 2955 | self.pending_tls_output |
| 2956 | .lock() |
| 2957 | .extend_from_slice(&buf[sent_total..]); |
| 2958 | return Err(create_ssl_want_write_error(vm).upcast()); |
| 2959 | } |
| 2960 | continue; |
| 2961 | } |
| 2962 | // Save unsent data for other errors too |
| 2963 | self.pending_tls_output |
| 2964 | .lock() |
| 2965 | .extend_from_slice(&buf[sent_total..]); |
| 2966 | return Err(e); |
| 2967 | } |
| 2968 | } |
| 2969 | } |
| 2970 | |
| 2971 | Ok(()) |
| 2972 | } |
no test coverage detected