mssql_browser/
browse_instance.rs1use super::error::*;
2use super::info::*;
3use super::socket::{UdpSocket, UdpSocketFactory};
4use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
5
6const CLNT_UCAST_INST: u8 = 0x04;
8
9const SVR_RESP: u8 = 0x05;
11
12#[cfg(any(feature = "tokio", feature = "async-std"))]
18pub async fn browse_instance(
19 remote_addr: IpAddr,
20 instance_name: &str,
21) -> Result<
22 InstanceInfo,
23 BrowserError<
24 <super::socket::DefaultSocketFactory as UdpSocketFactory>::Error,
25 <<super::socket::DefaultSocketFactory as UdpSocketFactory>::Socket as UdpSocket>::Error,
26 >,
27> {
28 let mut factory = super::socket::DefaultSocketFactory::new();
29 browse_instance_inner(remote_addr, instance_name, &mut factory).await
30}
31
32pub async fn browse_instance_inner<SF: UdpSocketFactory>(
38 remote_addr: IpAddr,
39 instance_name: &str,
40 socket_factory: &mut SF,
41) -> Result<InstanceInfo, BrowserError<SF::Error, <SF::Socket as UdpSocket>::Error>> {
42 if instance_name.len() > super::MAX_INSTANCE_NAME_LEN {
43 return Err(BrowserError::InstanceNameTooLong);
44 }
45
46 let local_addr = if remote_addr.is_ipv4() {
47 IpAddr::V4(Ipv4Addr::UNSPECIFIED)
48 } else {
49 IpAddr::V6(Ipv6Addr::UNSPECIFIED)
50 };
51
52 let bind_to = SocketAddr::new(local_addr, 0);
53 let mut socket = socket_factory
54 .bind(&bind_to)
55 .await
56 .map_err(BrowserError::BindFailed)?;
57
58 let remote = SocketAddr::new(remote_addr, 1434);
59 socket
60 .connect(&remote)
61 .await
62 .map_err(|e| BrowserError::ConnectFailed(remote, e))?;
63
64 let mut buffer = [0u8; 1 + super::MAX_INSTANCE_NAME_LEN + 1];
65 buffer[0] = CLNT_UCAST_INST;
66 buffer[1..(1 + instance_name.len())].copy_from_slice(instance_name.as_bytes()); let buffer_len = 2 + instance_name.len();
68 socket
69 .send_to(&buffer[0..buffer_len], &remote)
70 .await
71 .map_err(|e| BrowserError::SendFailed(remote, e))?;
72
73 let mut buffer = [0u8; 3 + 1024];
74
75 let bytes_received = socket
76 .recv(&mut buffer)
77 .await
78 .map_err(BrowserError::ReceiveFailed)?;
79
80 if bytes_received < 1 {
81 return Err(BrowserError::ProtocolError(
82 BrowserProtocolError::UnexpectedToken {
83 expected: BrowserProtocolToken::MessageIdentifier(SVR_RESP),
84 found: BrowserProtocolToken::EndOfMessage,
85 },
86 ));
87 }
88
89 if buffer[0] != SVR_RESP {
90 return Err(BrowserError::ProtocolError(
91 BrowserProtocolError::UnexpectedToken {
92 expected: BrowserProtocolToken::MessageIdentifier(SVR_RESP),
93 found: BrowserProtocolToken::MessageIdentifier(buffer[0]),
94 },
95 ));
96 }
97
98 if bytes_received < 3 {
99 return Err(BrowserError::ProtocolError(
100 BrowserProtocolError::UnexpectedToken {
101 expected: BrowserProtocolToken::MessageLength,
102 found: BrowserProtocolToken::EndOfMessage,
103 },
104 ));
105 }
106
107 let resp_data_len = u16::from_le_bytes([buffer[1], buffer[2]]);
108 if resp_data_len as usize != bytes_received - 3 {
109 return Err(BrowserError::ProtocolError(
110 BrowserProtocolError::LengthMismatch {
111 datagram: bytes_received,
112 header: (resp_data_len + 3) as usize,
113 },
114 ));
115 }
116
117 let as_str = std::str::from_utf8(&buffer[3..bytes_received]).unwrap();
119 let (instance, consumed) =
120 parse_instance_info(remote_addr, &as_str).map_err(|e| BrowserError::ProtocolError(e))?;
121
122 if consumed != as_str.len() {
123 return Err(BrowserError::ProtocolError(
124 BrowserProtocolError::ExtraneousData(Vec::from(&buffer[(3 + consumed)..])),
125 ));
126 }
127
128 Ok(instance)
129}