tiberius/
sql_browser.rs

1#[cfg(feature = "sql-browser-tokio")]
2mod tokio;
3
4#[cfg(feature = "sql-browser-async-std")]
5mod async_std;
6
7#[cfg(feature = "sql-browser-smol")]
8mod smol;
9
10use crate::client::Config;
11use async_trait::async_trait;
12
13/// An extension trait to a `TcpStream` to find a port and connecting to a
14/// named database instance.
15///
16/// Only needed on Windows platforms, where the server port is not known and the
17/// address is in the form of `hostname\\INSTANCE`.
18#[async_trait]
19pub trait SqlBrowser {
20    /// If the given builder defines a named instance, finds the correct port
21    /// and returns a `TcpStream` to be used in the [`Client`]. If instance name
22    /// is not defined, connects directly to the given host and port.
23    ///
24    /// [`Client`]: struct.Client.html
25    async fn connect_named(builder: &Config) -> crate::Result<Self>
26    where
27        Self: Sized + Send + Sync;
28}
29
30#[cfg(any(
31    feature = "sql-browser-async-std",
32    feature = "sql-browser-tokio",
33    feature = "sql-browser-smol"
34))]
35fn get_port_from_sql_browser_reply(
36    mut buf: Vec<u8>,
37    len: usize,
38    instance_name: &str,
39) -> crate::Result<u16> {
40    const DELIMITER: &[u8] = b"tcp;";
41
42    buf.truncate(len);
43
44    let err = crate::Error::Conversion(
45        format!("Could not resolve SQL browser instance {}", instance_name).into(),
46    );
47
48    if len == 0 {
49        return Err(err);
50    }
51
52    let rsp = &buf[3..len];
53
54    let port: u16 = rsp
55        .windows(DELIMITER.len())
56        .rev()
57        .position(|window| window == DELIMITER)
58        .and_then(|pos| rsp[(rsp.len() - pos)..].split(|item| *item == b';').next())
59        .ok_or(err)
60        .and_then(|val| Ok(std::str::from_utf8(val)?.parse()?))?;
61
62    Ok(port)
63}