mssql_browser/
browse_host.rs1use super::error::*;
2use super::info::*;
3use super::socket::{UdpSocket, UdpSocketFactory};
4use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
5
6const CLNT_UCAST_EX: u8 = 0x03;
9
10const SVR_RESP: u8 = 0x05;
12
13#[cfg(any(feature = "tokio", feature = "async-std"))]
19pub async fn browse_host(
20 remote_addr: IpAddr,
21) -> Result<
22 InstanceIterator,
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_host_inner(remote_addr, &mut factory).await
30}
31
32pub async fn browse_host_inner<SF: UdpSocketFactory>(
38 remote_addr: IpAddr,
39 socket_factory: &mut SF,
40) -> Result<InstanceIterator, BrowserError<SF::Error, <SF::Socket as UdpSocket>::Error>> {
41 let local_addr = if remote_addr.is_ipv4() {
42 IpAddr::V4(Ipv4Addr::UNSPECIFIED)
43 } else {
44 IpAddr::V6(Ipv6Addr::UNSPECIFIED)
45 };
46
47 let bind_to = SocketAddr::new(local_addr, 0);
48 let mut socket = socket_factory
49 .bind(&bind_to)
50 .await
51 .map_err(BrowserError::BindFailed)?;
52
53 let remote = SocketAddr::new(remote_addr, 1434);
54 socket
55 .connect(&remote)
56 .await
57 .map_err(|e| BrowserError::ConnectFailed(remote, e))?;
58
59 let buffer = [CLNT_UCAST_EX];
60 socket
61 .send_to(&buffer, &remote)
62 .await
63 .map_err(|e| BrowserError::SendFailed(remote, e))?;
64
65 let mut buffer = Vec::with_capacity(65535 + 3);
66
67 buffer.resize_with(buffer.capacity(), Default::default);
68
69 let bytes_received = socket
70 .recv(&mut buffer)
71 .await
72 .map_err(BrowserError::ReceiveFailed)?;
73
74 if bytes_received < 1 {
75 return Err(BrowserError::ProtocolError(
76 BrowserProtocolError::UnexpectedToken {
77 expected: BrowserProtocolToken::MessageIdentifier(SVR_RESP),
78 found: BrowserProtocolToken::EndOfMessage,
79 },
80 ));
81 }
82
83 if buffer[0] != SVR_RESP {
84 return Err(BrowserError::ProtocolError(
85 BrowserProtocolError::UnexpectedToken {
86 expected: BrowserProtocolToken::MessageIdentifier(SVR_RESP),
87 found: BrowserProtocolToken::MessageIdentifier(buffer[0]),
88 },
89 ));
90 }
91
92 if bytes_received < 3 {
93 return Err(BrowserError::ProtocolError(
94 BrowserProtocolError::UnexpectedToken {
95 expected: BrowserProtocolToken::MessageLength,
96 found: BrowserProtocolToken::EndOfMessage,
97 },
98 ));
99 }
100
101 let resp_data_len = u16::from_le_bytes([buffer[1], buffer[2]]);
102 if resp_data_len as usize != bytes_received - 3 {
103 return Err(BrowserError::ProtocolError(
104 BrowserProtocolError::LengthMismatch {
105 datagram: bytes_received,
106 header: (resp_data_len + 3) as usize,
107 },
108 ));
109 }
110
111 buffer.truncate(bytes_received);
112
113 std::str::from_utf8(&buffer[3..])
116 .map_err(|e| BrowserError::ProtocolError(BrowserProtocolError::InvalidUtf8(e)))?;
117
118 Ok(InstanceIterator {
119 remote_addr,
120 buffer,
121 offset: 3,
122 })
123}
124
125pub struct InstanceIterator {
127 remote_addr: IpAddr,
128 buffer: Vec<u8>,
129 offset: usize,
130}
131
132impl InstanceIterator {
133 pub fn next(
136 &mut self,
137 ) -> Result<
138 Option<InstanceInfo>,
139 BrowserError<std::convert::Infallible, std::convert::Infallible>,
140 > {
141 if self.offset == self.buffer.len() {
142 return Ok(None);
143 }
144
145 let as_str = unsafe { std::str::from_utf8_unchecked(&self.buffer[self.offset..]) };
147 let (instance, consumed) = parse_instance_info(self.remote_addr, as_str)
148 .map_err(|e| BrowserError::ProtocolError(e))?;
149
150 self.offset += consumed;
151 Ok(Some(instance))
152 }
153}