11use crate :: error:: Error ;
2+ use encoding_rs:: WINDOWS_1252 ;
23use sqlx_rt:: { timeout, UdpSocket } ;
3- use std:: borrow:: Cow ;
4- use std:: collections:: HashMap ;
54use std:: time:: Duration ;
65
76const SSRP_PORT : u16 = 1434 ;
87const CLNT_UCAST_INST : u8 = 0x04 ;
98const SVR_RESP : u8 = 0x05 ;
109const SSRP_TIMEOUT : Duration = Duration :: from_secs ( 1 ) ;
1110
11+ struct InstanceInfo < ' a > {
12+ server_name : Option < & ' a str > ,
13+ instance_name : Option < & ' a str > ,
14+ is_clustered : Option < & ' a str > ,
15+ version : Option < & ' a str > ,
16+ tcp_port : Option < & ' a str > ,
17+ }
18+
1219pub ( crate ) async fn resolve_instance_port ( server : & str , instance : & str ) -> Result < u16 , Error > {
1320 log:: debug!(
1421 "resolving SQL Server instance port for '{}' on server '{}'" ,
@@ -88,37 +95,27 @@ pub(crate) async fn resolve_instance_port(server: &str, instance: &str) -> Resul
8895 ) ) ;
8996 }
9097
91- let response_data = String :: from_utf8_lossy ( & buffer[ 3 ..( 3 + response_size) ] ) ;
98+ let response_bytes = & buffer[ 3 ..( 3 + response_size) ] ;
99+ let ( response_str, _encoding_used, had_errors) = WINDOWS_1252 . decode ( response_bytes) ;
100+
101+ if had_errors {
102+ log:: debug!( "SSRP response had MBCS decoding errors, continuing anyway" ) ;
103+ }
92104
93- log:: debug!( "SSRP response data: {}" , response_data ) ;
105+ log:: debug!( "SSRP response data: {}" , response_str ) ;
94106
95- parse_ssrp_response ( & response_data , instance)
107+ parse_ssrp_response ( & response_str , instance)
96108}
97109
98- fn parse_ssrp_response ( data : & Cow < ' _ , str > , instance_name : & str ) -> Result < u16 , Error > {
99- let instances: Vec < & str > = data. split ( ";;" ) . collect ( ) ;
100- log:: debug!(
101- "parsing SSRP response, found {} instance entries" ,
102- instances. len( )
103- ) ;
104-
105- for instance_data in instances {
110+ fn parse_ssrp_response ( data : & str , instance_name : & str ) -> Result < u16 , Error > {
111+ for instance_data in data. split ( ";;" ) {
106112 if instance_data. is_empty ( ) {
107113 continue ;
108114 }
109115
110- let tokens: Vec < & str > = instance_data. split ( ';' ) . collect ( ) ;
111- let mut properties: HashMap < & str , & str > = HashMap :: new ( ) ;
112-
113- let mut i = 0 ;
114- while i + 1 < tokens. len ( ) {
115- let key = tokens[ i] ;
116- let value = tokens[ i + 1 ] ;
117- properties. insert ( key, value) ;
118- i += 2 ;
119- }
120-
121- if let Some ( name) = properties. get ( "InstanceName" ) {
116+ let info = parse_instance_info ( instance_data) ;
117+
118+ if let Some ( name) = info. instance_name {
122119 log:: debug!( "found instance '{}' in SSRP response" , name) ;
123120
124121 if name. eq_ignore_ascii_case ( instance_name) {
@@ -128,7 +125,7 @@ fn parse_ssrp_response(data: &Cow<'_, str>, instance_name: &str) -> Result<u16,
128125 instance_name
129126 ) ;
130127
131- if let Some ( tcp_port_str) = properties . get ( "tcp" ) {
128+ if let Some ( tcp_port_str) = info . tcp_port {
132129 let port = tcp_port_str. parse :: < u16 > ( ) . map_err ( |e| {
133130 err_protocol ! (
134131 "invalid TCP port '{}' in SSRP response: {}" ,
@@ -160,6 +157,32 @@ fn parse_ssrp_response(data: &Cow<'_, str>, instance_name: &str) -> Result<u16,
160157 ) )
161158}
162159
160+ fn parse_instance_info < ' a > ( data : & ' a str ) -> InstanceInfo < ' a > {
161+ let mut info = InstanceInfo {
162+ server_name : None ,
163+ instance_name : None ,
164+ is_clustered : None ,
165+ version : None ,
166+ tcp_port : None ,
167+ } ;
168+
169+ let mut tokens = data. split ( ';' ) ;
170+ while let Some ( key) = tokens. next ( ) {
171+ let value = tokens. next ( ) ;
172+
173+ match key {
174+ "ServerName" => info. server_name = value,
175+ "InstanceName" => info. instance_name = value,
176+ "IsClustered" => info. is_clustered = value,
177+ "Version" => info. version = value,
178+ "tcp" => info. tcp_port = value,
179+ _ => { }
180+ }
181+ }
182+
183+ info
184+ }
185+
163186#[ cfg( test) ]
164187mod tests {
165188 use super :: * ;
0 commit comments