(
zelf: PyRef<Self>,
args: WrapBioArgs,
vm: &VirtualMachine,
)
| 2157 | |
| 2158 | #[pymethod] |
| 2159 | fn _wrap_bio( |
| 2160 | zelf: PyRef<Self>, |
| 2161 | args: WrapBioArgs, |
| 2162 | vm: &VirtualMachine, |
| 2163 | ) -> PyResult<PyObjectRef> { |
| 2164 | // Use common helper function |
| 2165 | let (ssl, socket_type, server_hostname) = |
| 2166 | Self::new_py_ssl_socket(zelf.clone(), args.server_side, args.server_hostname, vm)?; |
| 2167 | |
| 2168 | // Create BioStream wrapper |
| 2169 | let bio_stream = BioStream { |
| 2170 | inbio: args.incoming, |
| 2171 | outbio: args.outgoing, |
| 2172 | }; |
| 2173 | |
| 2174 | // Create SslStream with BioStream |
| 2175 | let stream = |
| 2176 | ssl::SslStream::new(ssl, bio_stream).map_err(|e| convert_openssl_error(vm, e))?; |
| 2177 | |
| 2178 | let py_ssl_socket = PySslSocket { |
| 2179 | ctx: PyRwLock::new(zelf.clone()), |
| 2180 | connection: PyRwLock::new(SslConnection::Bio(stream)), |
| 2181 | socket_type, |
| 2182 | server_hostname, |
| 2183 | owner: PyRwLock::new(args.owner.map(|o| o.downgrade(None, vm)).transpose()?), |
| 2184 | }; |
| 2185 | |
| 2186 | // Convert to PyRef (heap allocation) to avoid use-after-free |
| 2187 | let py_ref = |
| 2188 | py_ssl_socket.into_ref_with_type(vm, PySslSocket::class(&vm.ctx).to_owned())?; |
| 2189 | |
| 2190 | // Check if SNI callback is configured (minimize lock time) |
| 2191 | let has_sni_callback = zelf.sni_callback.lock().is_some(); |
| 2192 | |
| 2193 | // Set up ex_data for callbacks |
| 2194 | unsafe { |
| 2195 | let ssl_ptr = py_ref.connection.read().ssl().as_ptr(); |
| 2196 | |
| 2197 | // Clone and store via into_raw() - increments refcount and returns stable pointer |
| 2198 | // The refcount will be decremented by msg_callback_data_free when SSL is freed |
| 2199 | let cloned: PyObjectRef = py_ref.clone().into(); |
| 2200 | let raw_ptr = cloned.into_raw(); |
| 2201 | let msg_cb_idx = get_msg_callback_ex_data_index(); |
| 2202 | sys::SSL_set_ex_data(ssl_ptr, msg_cb_idx, raw_ptr.as_ptr() as *mut _); |
| 2203 | |
| 2204 | // Set SNI callback data if needed |
| 2205 | if has_sni_callback { |
| 2206 | let ssl_socket_weak = py_ref.as_object().downgrade(None, vm)?; |
| 2207 | // Store callback data in SSL ex_data - use weak reference to avoid cycle |
| 2208 | let callback_data = Box::new(SniCallbackData { |
| 2209 | ssl_context: zelf.clone(), |
| 2210 | ssl_socket_weak, |
| 2211 | }); |
| 2212 | let sni_idx = get_sni_ex_data_index(); |
| 2213 | sys::SSL_set_ex_data(ssl_ptr, sni_idx, Box::into_raw(callback_data) as *mut _); |
| 2214 | } |
| 2215 | } |
| 2216 |
nothing calls this directly
no test coverage detected