openssl_ktls/
stream.rs

1use std::os::fd::AsRawFd;
2
3use foreign_types_shared::ForeignType;
4
5use crate::ffi::BIO_NOCLOSE;
6
7pub struct SslStream {
8    _tcp: std::net::TcpStream,
9    ssl: openssl::ssl::Ssl,
10}
11impl SslStream {
12    /// Create a new SslStream from a tcp stream and SSL object.
13    pub fn new(tcp: std::net::TcpStream, ssl: openssl::ssl::Ssl) -> Self {
14        let sock_bio = unsafe { openssl_sys::BIO_new_socket(tcp.as_raw_fd(), BIO_NOCLOSE) };
15        assert!(!sock_bio.is_null(), "Failed to create socket BIO");
16        unsafe {
17            openssl_sys::SSL_set_bio(ssl.as_ptr(), sock_bio, sock_bio);
18        }
19        SslStream { _tcp: tcp, ssl }
20    }
21
22    /// Synchronous connect method (kept for backward compatibility)
23    pub fn connect(&self) -> Result<(), crate::error::Error> {
24        let result = unsafe { openssl_sys::SSL_connect(self.ssl.as_ptr()) };
25        if result <= 0 {
26            Err(crate::error::Error::make(result, self.ssl()))
27        } else {
28            Ok(())
29        }
30    }
31
32    pub fn accept(&self) -> Result<(), crate::error::Error> {
33        let result = unsafe { openssl_sys::SSL_accept(self.ssl.as_ptr()) };
34        if result <= 0 {
35            Err(crate::error::Error::make(result, self.ssl()))
36        } else {
37            Ok(())
38        }
39    }
40
41    pub fn ssl(&self) -> &openssl::ssl::Ssl {
42        &self.ssl
43    }
44
45    pub fn shutdown(&self) -> Result<(), crate::error::Error> {
46        let result = unsafe { openssl_sys::SSL_shutdown(self.ssl.as_ptr()) };
47        if result < 0 {
48            Err(crate::error::Error::make(result, self.ssl()))
49        } else {
50            Ok(())
51        }
52    }
53
54    pub fn ktls_send_enabled(&self) -> bool {
55        unsafe {
56            let wbio = openssl_sys::SSL_get_wbio(self.ssl.as_ptr());
57            crate::ffi::BIO_get_ktls_send(wbio) != 0
58        }
59    }
60
61    pub fn ktls_recv_enabled(&self) -> bool {
62        unsafe {
63            let rbio = openssl_sys::SSL_get_rbio(self.ssl.as_ptr());
64            crate::ffi::BIO_get_ktls_recv(rbio) != 0
65        }
66    }
67}
68
69impl std::io::Read for SslStream {
70    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
71        unsafe {
72            let len = openssl_sys::SSL_read(
73                self.ssl.as_ptr(),
74                buf.as_mut_ptr() as *mut _,
75                buf.len().try_into().unwrap(),
76            );
77            if len < 0 {
78                Err(std::io::Error::other(crate::error::Error::make(
79                    len,
80                    self.ssl(),
81                )))
82            } else {
83                Ok(len as usize)
84            }
85        }
86    }
87}
88
89impl std::io::Write for SslStream {
90    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
91        if buf.is_empty() {
92            return Ok(0);
93        }
94
95        unsafe {
96            let len = openssl_sys::SSL_write(
97                self.ssl.as_ptr(),
98                buf.as_ptr() as *const _,
99                buf.len().try_into().unwrap(),
100            );
101            if len < 0 {
102                Err(std::io::Error::other(crate::error::Error::make(
103                    len,
104                    self.ssl(),
105                )))
106            } else {
107                Ok(len as usize)
108            }
109        }
110    }
111
112    fn flush(&mut self) -> std::io::Result<()> {
113        Ok(())
114    }
115}
116
117impl Drop for SslStream {
118    fn drop(&mut self) {
119        // The BIO is automatically freed when SSL_free is called on the SSL object,
120        // so we don't need to manually free the BIO here. The SSL object will be
121        // dropped automatically via its Drop implementation.
122        //
123        // Note: We used SSL_set_bio(ssl, bio, bio) which means both read and write
124        // BIOs point to the same BIO object, and SSL takes ownership of it.
125    }
126}