tiberius_rustls/sql_browser/
smol.rs1use super::SqlBrowser;
2use crate::client::Config;
3use async_io::Timer;
4use async_net::{resolve, TcpStream, UdpSocket};
5use async_trait::async_trait;
6use futures_lite::FutureExt;
7use futures_util::future::TryFutureExt;
8use std::io;
9use std::time::Duration;
10use tracing::Level;
11
12#[async_trait]
13impl SqlBrowser for TcpStream {
14 async fn connect_named(builder: &Config) -> crate::Result<Self> {
18 let addrs = resolve(builder.get_addr()).await?;
19
20 for mut addr in addrs {
21 if let Some(ref instance_name) = builder.instance_name {
22 let local_bind: std::net::SocketAddr = if addr.is_ipv4() {
27 "0.0.0.0:0".parse().unwrap()
28 } else {
29 "[::]:0".parse().unwrap()
30 };
31
32 tracing::event!(
33 Level::TRACE,
34 "Connecting to instance `{}` using SQL Browser in port `{}`",
35 instance_name,
36 builder.get_port()
37 );
38
39 let msg = [&[4u8], instance_name.as_bytes()].concat();
40 let mut buf = vec![0u8; 4096];
41
42 let socket = UdpSocket::bind(&local_bind).await?;
43 socket.send_to(&msg, &addr).await?;
44
45 let timeout = Duration::from_millis(1000);
46
47 let len = socket.recv(&mut buf).or(async {
48 Timer::after(timeout).await;
49 Err(std::io::ErrorKind::TimedOut.into())
50 })
51 .map_err(|e| {
52 if e.kind() == std::io::ErrorKind::TimedOut {
53 crate::error::Error::Conversion(
54 format!(
55 "SQL browser timeout during resolving instance {}. Please check if browser is running in port {} and does the instance exist.",
56 instance_name,
57 builder.get_port(),
58 )
59 .into(),
60 )
61 } else {
62 e.into()
63 }
64 }).await?;
65
66 let port = super::get_port_from_sql_browser_reply(buf, len, instance_name)?;
67 tracing::event!(Level::TRACE, "Found port `{}` from SQL Browser", port);
68 addr.set_port(port);
69 };
70
71 if let Ok(stream) = TcpStream::connect(addr).await {
72 stream.set_nodelay(true)?;
73 return Ok(stream);
74 }
75 }
76
77 Err(io::Error::new(io::ErrorKind::NotFound, "Could not resolve server host").into())
78 }
79}