1pub fn decode_bind_single(body: &[u8]) -> Result<(), String> {
24 const RPC_RESULT: u32 = 0xf35c6d01;
25 const BOOL_TRUE: u32 = 0x9972_75b5;
26 const BOOL_FALSE: u32 = 0xbc79_9737;
27 const RPC_ERROR: u32 = 0x2144_ca19;
28 const BAD_MSG: u32 = 0xa7ef_f811;
29 const BAD_SALT: u32 = 0xedab_447b;
30 const NEW_SESSION: u32 = 0x9ec2_0908;
31 const FUTURE_SALTS: u32 = 0xae50_0895;
32 const MSGS_ACK: u32 = 0x62d6_b459;
33 const PONG: u32 = 0x0347_73c5;
34
35 if body.len() < 4 {
36 return Err("skip".to_string());
37 }
38 let ctor = u32::from_le_bytes(body[..4].try_into().unwrap());
39
40 match ctor {
41 BOOL_TRUE => Ok(()),
42
43 BOOL_FALSE => Err("server returned boolFalse (binding rejected)".to_string()),
44
45 NEW_SESSION | FUTURE_SALTS | MSGS_ACK | PONG => Err("skip".to_string()),
46
47 RPC_RESULT if body.len() >= 16 => {
48 let inner = u32::from_le_bytes(body[12..16].try_into().unwrap());
49 match inner {
50 BOOL_TRUE => Ok(()),
51 BOOL_FALSE => Err("rpc_result{boolFalse} (server rejected binding)".to_string()),
52 RPC_ERROR if body.len() >= 20 => {
53 let code = i32::from_le_bytes(body[16..20].try_into().unwrap());
54 let msg = crate::util::tl_read_string(body.get(20..).unwrap_or(&[]))
55 .unwrap_or_default();
56 Err(format!("rpc_error code={code} message={msg:?}"))
57 }
58 _ => Err(format!("rpc_result inner ctor={inner:#010x}")),
59 }
60 }
61
62 BAD_MSG if body.len() >= 16 => {
63 let code = u32::from_le_bytes(body[12..16].try_into().unwrap());
64 let desc = match code {
65 16 => "msg_id too low (clock skew)",
66 17 => "msg_id too high (clock skew)",
67 18 => "incorrect lower 2 bits of msg_id",
68 19 => "duplicate msg_id",
69 20 => "message too old (>300s)",
70 32 => "msg_seqno too low",
71 33 => "msg_seqno too high",
72 34 => "even seqno expected, odd received",
73 35 => "odd seqno expected, even received",
74 48 => "incorrect server salt",
75 64 => "invalid container",
76 _ => "unknown code",
77 };
78 Err(format!("bad_msg_notification code={code} ({desc})"))
79 }
80
81 BAD_SALT if body.len() >= 24 => {
82 let new_salt = i64::from_le_bytes(body[16..24].try_into().unwrap());
83 Err(format!(
84 "bad_server_salt, server wants salt={new_salt:#018x}"
85 ))
86 }
87
88 _ => Err(format!("unknown ctor={ctor:#010x}")),
89 }
90}
91
92pub fn decode_bind_response(body: &[u8]) -> Result<(), String> {
98 const MSG_CONTAINER: u32 = 0x73f1f8dc;
99
100 if body.len() < 4 {
101 return Err(format!("response body too short ({} bytes)", body.len()));
102 }
103 let ctor = u32::from_le_bytes(body[..4].try_into().unwrap());
104
105 if ctor != MSG_CONTAINER {
106 return decode_bind_single(body).map_err(|e| {
107 if e == "skip" {
108 "__need_more__".to_string()
109 } else {
110 e
111 }
112 });
113 }
114
115 if body.len() < 8 {
116 return Err("msg_container too short to read count".to_string());
117 }
118 let count = u32::from_le_bytes(body[4..8].try_into().unwrap()) as usize;
119 let mut pos = 8usize;
120 let mut last_real_err: Option<String> = None;
121
122 for i in 0..count {
123 if pos + 16 > body.len() {
124 return Err(format!(
125 "msg_container truncated at message {i}/{count} (pos={pos} body_len={})",
126 body.len()
127 ));
128 }
129 let msg_bytes = u32::from_le_bytes(body[pos + 12..pos + 16].try_into().unwrap()) as usize;
130 pos += 16;
131
132 if pos + msg_bytes > body.len() {
133 return Err(format!(
134 "msg_container message {i} body overflows (need {msg_bytes}, have {})",
135 body.len() - pos
136 ));
137 }
138 let msg_body = &body[pos..pos + msg_bytes];
139 pos += msg_bytes;
140
141 match decode_bind_single(msg_body) {
142 Ok(()) => return Ok(()),
143 Err(e) if e == "skip" => continue,
144 Err(e) => {
145 last_real_err = Some(e);
146 }
147 }
148 }
149
150 Err(last_real_err.unwrap_or_else(|| "__need_more__".to_string()))
151}