1use super::error::{BrowserProtocolError, BrowserProtocolField, BrowserProtocolToken};
2use std::net::IpAddr;
3
4#[derive(Debug)]
7pub struct InstanceInfo {
8 pub addr: IpAddr,
10
11 pub server_name: String,
13
14 pub instance_name: String,
17
18 pub is_clustered: bool,
19
20 pub version: String,
23
24 pub np_info: Option<NamedPipeInfo>,
25 pub tcp_info: Option<TcpInfo>,
26 pub via_info: Option<ViaInfo>,
27 pub rpc_info: Option<RpcInfo>,
28 pub spx_info: Option<SpxInfo>,
29 pub adsp_info: Option<AdspInfo>,
30 pub bv_info: Option<BvInfo>,
31}
32
33#[derive(Debug)]
35pub struct NamedPipeInfo {
36 pub name: String,
38}
39
40#[derive(Debug)]
42pub struct TcpInfo {
43 pub port: u16,
46}
47
48#[derive(Debug)]
50pub struct ViaInfo {
51 pub machine_name: String,
53
54 pub addresses: Vec<ViaAddress>,
56}
57
58#[derive(Debug)]
60pub struct ViaAddress {
61 pub nic: String,
64
65 pub port: String,
68}
69
70#[derive(Debug)]
72pub struct RpcInfo {
73 pub computer_name: String,
75}
76
77#[derive(Debug)]
79pub struct SpxInfo {
80 pub service_name: String,
83}
84
85#[derive(Debug)]
87pub struct AdspInfo {
88 pub object_name: String,
90}
91
92#[derive(Debug)]
94pub struct BvInfo {
95 pub item_name: String,
97
98 pub group_name: String,
100
101 pub org_name: String,
103}
104
105#[derive(Debug)]
107pub struct DacInfo {
108 pub port: u16,
109}
110
111struct SplitIteratorWithPosition<'a> {
112 inner: std::str::Split<'a, char>,
113 position: usize,
114}
115
116impl<'a> SplitIteratorWithPosition<'a> {
117 fn new(inner: std::str::Split<'a, char>) -> SplitIteratorWithPosition<'a> {
118 SplitIteratorWithPosition {
119 inner: inner,
120 position: 0,
121 }
122 }
123
124 fn string_position(&self) -> usize {
125 self.position
126 }
127}
128
129impl<'a> Iterator for SplitIteratorWithPosition<'a> {
130 type Item = &'a str;
131
132 fn next(&mut self) -> Option<&'a str> {
133 match self.inner.next() {
134 Some(x) => {
135 self.position += x.len() + 1;
136 Some(x)
137 }
138 None => None,
139 }
140 }
141}
142
143pub(crate) fn parse_instance_info(
144 addr: IpAddr,
145 string: &str,
146) -> Result<(InstanceInfo, usize), BrowserProtocolError> {
147 #[inline]
148 fn expect_next<'a, T: Iterator<Item = &'a str>>(
149 iterator: &mut T,
150 identifier: &str,
151 field: BrowserProtocolField,
152 ) -> Result<(), BrowserProtocolError> {
153 iterator
154 .next()
155 .ok_or_else(|| BrowserProtocolError::UnexpectedToken {
156 expected: BrowserProtocolToken::Identifier(field),
157 found: BrowserProtocolToken::EndOfMessage,
158 })
159 .and_then(|x| {
160 if x == identifier {
161 Ok(())
162 } else {
163 Err(BrowserProtocolError::UnexpectedToken {
164 expected: BrowserProtocolToken::Identifier(field),
165 found: BrowserProtocolToken::Literal(x.to_string()),
166 })
167 }
168 })
169 }
170
171 fn consume_next<'a, T: Iterator<Item = &'a str>>(
172 iterator: &mut T,
173 value_name: BrowserProtocolField,
174 ) -> Result<&'a str, BrowserProtocolError> {
175 iterator
176 .next()
177 .ok_or_else(|| BrowserProtocolError::UnexpectedToken {
178 expected: BrowserProtocolToken::ValueOf(value_name),
179 found: BrowserProtocolToken::EndOfMessage,
180 })
181 }
182
183 let mut iterator = SplitIteratorWithPosition::new(string.split(';'));
184
185 expect_next(
187 &mut iterator,
188 "ServerName",
189 BrowserProtocolField::ServerName,
190 )?;
191 let server_name = consume_next(&mut iterator, BrowserProtocolField::ServerName)?;
192 expect_next(
193 &mut iterator,
194 "InstanceName",
195 BrowserProtocolField::InstanceName,
196 )?;
197 let instance_name = consume_next(&mut iterator, BrowserProtocolField::InstanceName)?;
198 expect_next(
199 &mut iterator,
200 "IsClustered",
201 BrowserProtocolField::IsClustered,
202 )?;
203 let is_clustered_str = consume_next(&mut iterator, BrowserProtocolField::IsClustered)?;
204 let is_clustered = match is_clustered_str {
205 "Yes" => true,
206 "No" => false,
207 v => {
208 return Err(BrowserProtocolError::UnexpectedToken {
209 expected: BrowserProtocolToken::ValueOf(BrowserProtocolField::IsClustered),
210 found: BrowserProtocolToken::Literal(v.to_string()),
211 })
212 }
213 };
214 expect_next(&mut iterator, "Version", BrowserProtocolField::Version)?;
215 let version = consume_next(&mut iterator, BrowserProtocolField::Version)?;
216
217 let mut np_info: Option<NamedPipeInfo> = None;
219 let mut tcp_info: Option<TcpInfo> = None;
220 let mut via_info: Option<ViaInfo> = None;
221 let mut rpc_info: Option<RpcInfo> = None;
222 let mut spx_info: Option<SpxInfo> = None;
223 let mut adsp_info: Option<AdspInfo> = None;
224 let mut bv_info: Option<BvInfo> = None;
225
226 loop {
227 match iterator.next() {
228 Some("np") => {
229 let pipe_name = consume_next(&mut iterator, BrowserProtocolField::NamedPipeName)?;
230 np_info = Some(NamedPipeInfo {
231 name: pipe_name.to_owned(),
232 });
233 }
234 Some("tcp") => {
235 let port_str = consume_next(&mut iterator, BrowserProtocolField::TcpPort)?;
236 let port: u16 =
237 port_str
238 .parse()
239 .map_err(|_| BrowserProtocolError::UnexpectedToken {
240 expected: BrowserProtocolToken::TcpPort,
241 found: BrowserProtocolToken::Literal(port_str.to_string()),
242 })?;
243 tcp_info = Some(TcpInfo { port });
244 }
245 Some("via") => {
246 let parameters = consume_next(&mut iterator, BrowserProtocolField::ViaMachineName)?;
247 let comma_idx =
248 parameters
249 .find(',')
250 .ok_or_else(|| BrowserProtocolError::UnexpectedToken {
251 expected: BrowserProtocolToken::ViaParameters,
252 found: BrowserProtocolToken::Literal(parameters.to_string()),
253 })?;
254 let machine_name = ¶meters[0..comma_idx];
255 let mut nic_port_parts = (¶meters[(comma_idx + 1)..]).split(&[',', ':'][..]);
256 let mut addresses = Vec::new();
257 while let Some(nic) = nic_port_parts.next() {
258 let port = nic_port_parts.next().ok_or_else(|| {
259 BrowserProtocolError::UnexpectedToken {
260 expected: BrowserProtocolToken::ViaParameters,
261 found: BrowserProtocolToken::Literal(parameters.to_string()),
262 }
263 })?;
264 addresses.push(ViaAddress {
265 nic: nic.to_owned(),
266 port: port.to_owned(),
267 });
268 }
269 via_info = Some(ViaInfo {
270 machine_name: machine_name.to_owned(),
271 addresses,
272 });
273 }
274 Some("rpc") => {
275 let computer_name =
276 consume_next(&mut iterator, BrowserProtocolField::RpcComputerName)?;
277 rpc_info = Some(RpcInfo {
278 computer_name: computer_name.to_owned(),
279 });
280 }
281 Some("spx") => {
282 let service_name =
283 consume_next(&mut iterator, BrowserProtocolField::SpxServiceName)?;
284 spx_info = Some(SpxInfo {
285 service_name: service_name.to_owned(),
286 });
287 }
288 Some("adsp") => {
289 let object_name =
290 consume_next(&mut iterator, BrowserProtocolField::AppleTalkObjectName)?;
291 adsp_info = Some(AdspInfo {
292 object_name: object_name.to_owned(),
293 });
294 }
295 Some("bv") => {
296 let item_name = consume_next(&mut iterator, BrowserProtocolField::BvItemName)?;
297 let group_name = consume_next(&mut iterator, BrowserProtocolField::BvGroupName)?;
298 let org_name = consume_next(&mut iterator, BrowserProtocolField::BvOrgName)?;
299 bv_info = Some(BvInfo {
300 item_name: item_name.to_owned(),
301 group_name: group_name.to_owned(),
302 org_name: org_name.to_owned(),
303 });
304 }
305 Some("") => break,
306 Some(x) => {
307 return Err(BrowserProtocolError::UnexpectedToken {
308 expected: BrowserProtocolToken::EndpointIdentifierOrSemicolon,
309 found: BrowserProtocolToken::Literal(x.to_string()),
310 })
311 }
312 None => {
313 return Err(BrowserProtocolError::UnexpectedToken {
314 expected: BrowserProtocolToken::EndpointIdentifierOrSemicolon,
315 found: BrowserProtocolToken::EndOfMessage,
316 })
317 }
318 };
319 }
320
321 let consumed = iterator.string_position();
322
323 Ok((
324 InstanceInfo {
325 addr,
326 server_name: server_name.to_owned(),
327 instance_name: instance_name.to_owned(),
328 is_clustered,
329 version: version.to_owned(),
330 np_info,
331 tcp_info,
332 via_info,
333 rpc_info,
334 spx_info,
335 adsp_info,
336 bv_info,
337 },
338 consumed,
339 ))
340}