tiberius_rustls/sql_browser/
async_std.rs

1use super::SqlBrowser;
2use async_std::{
3    io,
4    net::{self, ToSocketAddrs},
5};
6use async_trait::async_trait;
7use futures_util::future::TryFutureExt;
8use std::time;
9use tracing::Level;
10
11#[async_trait]
12impl SqlBrowser for net::TcpStream {
13    /// This method can be used to connect to SQL Server named instances
14    /// when on a Windows platform with the `sql-browser-async-std` feature
15    /// enabled. Please see the crate examples for more detailed examples.
16    async fn connect_named(builder: &crate::client::Config) -> crate::Result<Self> {
17        let addrs = builder.get_addr().to_socket_addrs().await?;
18
19        for mut addr in addrs {
20            if let Some(ref instance_name) = builder.instance_name {
21                // First resolve the instance to a port via the
22                // SSRP protocol/MS-SQLR protocol [1]
23                // [1] https://msdn.microsoft.com/en-us/library/cc219703.aspx
24
25                let local_bind: std::net::SocketAddr = if addr.is_ipv4() {
26                    "0.0.0.0:0".parse().unwrap()
27                } else {
28                    "[::]:0".parse().unwrap()
29                };
30
31                tracing::event!(
32                    Level::TRACE,
33                    "Connecting to instance `{}` using SQL Browser in port `{}`",
34                    instance_name,
35                    builder.get_port()
36                );
37
38                let msg = [&[4u8], instance_name.as_bytes()].concat();
39                let mut buf = vec![0u8; 4096];
40
41                let socket = net::UdpSocket::bind(&local_bind).await?;
42                socket.send_to(&msg, &addr).await?;
43
44                let timeout = time::Duration::from_millis(1000);
45
46                let len = io::timeout(timeout, socket.recv(&mut buf))
47                    .map_err(|_| {
48                        crate::error::Error::Conversion(
49                            format!(
50                                "SQL browser timeout during resolving instance {}. Please check if browser is running in port {} and does the instance exist.",
51                                instance_name,
52                                builder.get_port(),
53                            )
54                            .into(),
55                        )
56                    })
57                    .await?;
58
59                let port = super::get_port_from_sql_browser_reply(buf, len, instance_name)?;
60                tracing::event!(Level::TRACE, "Found port `{}` from SQL Browser", port);
61                addr.set_port(port);
62            };
63
64            if let Ok(stream) = net::TcpStream::connect(addr).await {
65                stream.set_nodelay(true)?;
66                return Ok(stream);
67            }
68        }
69
70        Err(io::Error::new(io::ErrorKind::NotFound, "Could not resolve server host").into())
71    }
72}